@fotor-ai/dsh-fotor-plugin 0.6.0 → 0.6.1-test.2
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/INSTALL.md +46 -127
- package/README.md +27 -24
- package/configuration.example.yml +3 -2
- package/cordis.patch.yml +7 -15
- package/package.json +8 -2
- package/runtime/client.mjs +84 -0
- package/runtime/config.mjs +95 -0
- package/runtime/lease.mjs +25 -0
- package/runtime/lifecycle.mjs +65 -0
- package/runtime/mcp.mjs +34 -0
- package/runtime/skills.mjs +19 -0
- package/skills/fotor-connect/references/authentication.md +17 -25
- package/skills/fotor-connect/references/mcp-integration.md +1 -1
- package/skills/fotor-credits/references/authentication.md +17 -25
- package/skills/fotor-credits/references/mcp-integration.md +1 -1
- package/skills/fotor-image/references/authentication.md +17 -25
- package/skills/fotor-image/references/mcp-integration.md +1 -1
- package/skills/fotor-upload/references/authentication.md +17 -25
- package/skills/fotor-upload/references/mcp-integration.md +1 -1
- package/skills/fotor-video/references/authentication.md +17 -25
- package/skills/fotor-video/references/mcp-integration.md +1 -1
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/** Resolve installed resources without persisting machine-specific configuration. */
|
|
2
|
+
import { access, readFile, realpath, stat } from 'node:fs/promises';
|
|
3
|
+
import { constants } from 'node:fs';
|
|
4
|
+
import { createRequire } from 'node:module';
|
|
5
|
+
import { execFile } from 'node:child_process';
|
|
6
|
+
import { promisify } from 'node:util';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
|
|
10
|
+
export const PACKAGE_ROOT = fileURLToPath(new URL('../', import.meta.url));
|
|
11
|
+
export const ENDPOINT = 'https://mcp.fotor.com/mcp';
|
|
12
|
+
export const CALLBACK_HOST = '127.0.0.1';
|
|
13
|
+
const execute = promisify(execFile);
|
|
14
|
+
export function supportedNode(version) {
|
|
15
|
+
const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.exec(version);
|
|
16
|
+
return !!match && ((Number(match[1]) === 24 && Number(match[2]) >= 2) || Number(match[1]) === 26);
|
|
17
|
+
}
|
|
18
|
+
export function requireValue(condition, message) {
|
|
19
|
+
if (!condition) throw new Error('Fotor configuration: ' + message);
|
|
20
|
+
}
|
|
21
|
+
export function inputObject(input) {
|
|
22
|
+
requireValue(input !== null && typeof input === 'object' && !Array.isArray(input), 'expected an object');
|
|
23
|
+
return input;
|
|
24
|
+
}
|
|
25
|
+
async function absoluteResource(value, directory = false) {
|
|
26
|
+
requireValue(typeof value === 'string' && path.isAbsolute(value), 'use an absolute resource path');
|
|
27
|
+
const info = await stat(value).catch(() => null);
|
|
28
|
+
requireValue(info && (directory ? info.isDirectory() : info.isFile()), 'configured resource is missing; preserve the override or remove it to use automatic resolution');
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
function serviceUrl(value) {
|
|
32
|
+
const url = new URL(value);
|
|
33
|
+
requireValue(!url.username && !url.password && !url.hash, 'invalid service URL');
|
|
34
|
+
requireValue(url.href === ENDPOINT || (url.protocol === 'http:' && ['127.0.0.1', '[::1]', 'localhost'].includes(url.hostname)), 'only production Fotor or a loopback acceptance service is supported');
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
export async function resolveSkills(input = {}, options = {}) {
|
|
38
|
+
inputObject(input);
|
|
39
|
+
const packageRoot = options.packageRoot ?? PACKAGE_ROOT;
|
|
40
|
+
requireValue(input.includeDefaultRoots === undefined || input.includeDefaultRoots === false, 'default skill roots must stay disabled');
|
|
41
|
+
const roots = input.customSkillDirs ?? [path.join(packageRoot, 'skills')];
|
|
42
|
+
requireValue(Array.isArray(roots) && roots.length === 1, 'configure one Fotor skill root or remove customSkillDirs for automatic resolution');
|
|
43
|
+
await absoluteResource(roots[0], true);
|
|
44
|
+
return { ...input, providerName: input.providerName ?? 'fotor', includeDefaultRoots: false, customSkillDirs: [...roots], watch: input.watch ?? false };
|
|
45
|
+
}
|
|
46
|
+
export async function resolveMcp(input = {}, options = {}) {
|
|
47
|
+
inputObject(input);
|
|
48
|
+
const packageRoot = options.packageRoot ?? PACKAGE_ROOT;
|
|
49
|
+
const profileDir = options.profileDir;
|
|
50
|
+
requireValue(typeof profileDir === 'string' && path.isAbsolute(profileDir), 'an active profile is required');
|
|
51
|
+
requireValue(input.transport === undefined || input.transport === 'stdio', 'expected the managed stdio transport');
|
|
52
|
+
requireValue(input.reconnect === undefined || input.reconnect.enabled === false, 'automatic host reconnect must stay disabled');
|
|
53
|
+
const command = input.command ?? process.execPath;
|
|
54
|
+
await absoluteResource(command);
|
|
55
|
+
await access(command, constants.X_OK);
|
|
56
|
+
const version = command === process.execPath ? process.versions.node : (await execute(command, ['--version'], { timeout: 5000, env: childEnvironment({}) })).stdout.trim().replace(/^v/, '');
|
|
57
|
+
requireValue(supportedNode(version), 'use stable Node 24.2.0 or later in 24.x, or Node 26.x');
|
|
58
|
+
const suppliedArgs = input.args;
|
|
59
|
+
requireValue(suppliedArgs === undefined || (Array.isArray(suppliedArgs) && suppliedArgs.length >= 2 && suppliedArgs.every(value => typeof value === 'string')), 'args must be a complete bridge argument array');
|
|
60
|
+
const proxy = suppliedArgs?.[0] ?? path.join(path.dirname(createRequire(path.join(packageRoot, 'package.json')).resolve('mcp-remote/package.json')), 'dist/proxy.js');
|
|
61
|
+
await absoluteResource(proxy);
|
|
62
|
+
requireValue(path.basename(proxy) === 'proxy.js', 'expected the mcp-remote proxy entry');
|
|
63
|
+
const bridgeRoot = path.dirname(path.dirname(await realpath(proxy)));
|
|
64
|
+
const manifest = JSON.parse(await readFile(path.join(bridgeRoot, 'package.json'), 'utf8'));
|
|
65
|
+
requireValue(manifest.name === 'mcp-remote' && manifest.version === '0.15.2', 'expected installed mcp-remote 0.15.2');
|
|
66
|
+
const client = path.join(bridgeRoot, 'dist/client.js');
|
|
67
|
+
await absoluteResource(client);
|
|
68
|
+
const endpoint = serviceUrl(suppliedArgs?.[1] ?? input.endpoint ?? ENDPOINT);
|
|
69
|
+
const callbackPort = input.callbackPort ?? 3335;
|
|
70
|
+
requireValue(Number.isInteger(callbackPort) && callbackPort > 0 && callbackPort < 65536, 'invalid callback port');
|
|
71
|
+
const args = suppliedArgs ? [...suppliedArgs] : [proxy, endpoint, String(callbackPort), '--host', CALLBACK_HOST, '--transport', 'http-only', '--resource', endpoint, '--auth-timeout', '600', '--connect-timeout', '20', '--headers-timeout', '20', '--body-timeout', '20'];
|
|
72
|
+
requireValue(!args.some(value => ['--allow-http', '--skip-resource-parameter', '--debug'].includes(value)), 'unsafe or sensitive-output bridge option');
|
|
73
|
+
const option = name => args[args.indexOf(name) + 1];
|
|
74
|
+
requireValue(args.includes('--resource') && option('--resource') === endpoint, 'preserve the MCP resource parameter');
|
|
75
|
+
requireValue(!args.includes('--host') || option('--host') === CALLBACK_HOST, 'callback must stay on the loopback host');
|
|
76
|
+
const env = { ...inputObject(input.env ?? {}) };
|
|
77
|
+
requireValue(Object.values(env).every(value => typeof value === 'string'), 'environment values must be strings');
|
|
78
|
+
requireValue(env.NODE_TLS_REJECT_UNAUTHORIZED !== '0', 'TLS verification must stay enabled');
|
|
79
|
+
env.MCP_REMOTE_CONFIG_DIR ??= path.join(profileDir, 'fotor', 'mcp-auth');
|
|
80
|
+
requireValue(path.isAbsolute(env.MCP_REMOTE_CONFIG_DIR), 'the credential directory must be absolute');
|
|
81
|
+
const relative = path.relative(packageRoot, env.MCP_REMOTE_CONFIG_DIR);
|
|
82
|
+
requireValue(relative.startsWith('..' + path.sep) || path.isAbsolute(relative), 'credentials must be outside the installed package');
|
|
83
|
+
const cwd = await absoluteResource(input.cwd ?? options.cwd ?? profileDir, true);
|
|
84
|
+
const { endpoint: _endpoint, callbackPort: _callback, ...nativeInput } = input;
|
|
85
|
+
return {
|
|
86
|
+
client,
|
|
87
|
+
native: { ...nativeInput, transport: 'stdio', serverName: input.serverName ?? 'fotor', command, args, env, cwd,
|
|
88
|
+
toolCallTimeoutMs: input.toolCallTimeoutMs ?? 25000, failOnStartupError: input.failOnStartupError ?? true, reconnect: { ...input.reconnect, enabled: false } },
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/** Share desktop routing, but never copy ambient account credentials into the child. */
|
|
92
|
+
export function childEnvironment(extra) {
|
|
93
|
+
const keys = ['PATH', 'HOME', 'USER', 'LOGNAME', 'LANG', 'LC_ALL', 'DISPLAY', 'WAYLAND_DISPLAY', 'DBUS_SESSION_BUS_ADDRESS', 'XDG_RUNTIME_DIR', 'XDG_CONFIG_HOME', 'XDG_DATA_HOME', 'XDG_CURRENT_DESKTOP', 'DESKTOP_SESSION', 'BROWSER', 'HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY', 'http_proxy', 'https_proxy', 'no_proxy', 'NODE_EXTRA_CA_CERTS'];
|
|
94
|
+
return { ...Object.fromEntries(keys.filter(key => process.env[key] !== undefined).map(key => [key, process.env[key]])), ...extra };
|
|
95
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Reserve one external Fotor store across host processes without reading credentials. */
|
|
2
|
+
import { constants } from 'node:fs';
|
|
3
|
+
import { mkdir, open, lstat, unlink } from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
|
|
6
|
+
export async function acquireLease(directory) {
|
|
7
|
+
await mkdir(path.dirname(directory), { recursive: true, mode: 0o700 });
|
|
8
|
+
const filename = directory + '.connection-lock';
|
|
9
|
+
let handle;
|
|
10
|
+
try { handle = await open(filename, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 0o600); }
|
|
11
|
+
catch (error) {
|
|
12
|
+
if (error.code === 'EEXIST') throw new Error('Fotor connection lock exists; stop the other connection or inspect this adapter-owned lock before retrying');
|
|
13
|
+
throw new Error('Fotor connection lock could not be created');
|
|
14
|
+
}
|
|
15
|
+
const identity = await handle.stat();
|
|
16
|
+
try { await handle.writeFile(JSON.stringify({ pid: process.pid }) + '\n'); }
|
|
17
|
+
finally { await handle.close(); }
|
|
18
|
+
let released = false;
|
|
19
|
+
return async () => {
|
|
20
|
+
if (released) return;
|
|
21
|
+
released = true;
|
|
22
|
+
const current = await lstat(filename).catch(() => null);
|
|
23
|
+
if (current?.isFile() && current.ino === identity.ino && current.dev === identity.dev) await unlink(filename);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/** One cancellable connection owner; activation never waits for human consent. */
|
|
2
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
3
|
+
import { authorize, checkCallbackPort } from './client.mjs';
|
|
4
|
+
import { acquireLease } from './lease.mjs';
|
|
5
|
+
|
|
6
|
+
const owners = new Map();
|
|
7
|
+
export function startConnection(connection, { mount, status, authorizeClient = authorize, lease = acquireLease, checkPort = checkCallbackPort, wait = delay, automaticMs = 90000 }) {
|
|
8
|
+
const key = connection.native.env.MCP_REMOTE_CONFIG_DIR + '\n' + connection.native.args[1];
|
|
9
|
+
if (owners.has(key)) throw new Error('Fotor connection already active for this credential directory');
|
|
10
|
+
const controller = new AbortController();
|
|
11
|
+
let releaseLease;
|
|
12
|
+
let child, state = 'preparing', diagnostic;
|
|
13
|
+
const publish = (next, message) => { state = next; diagnostic = message; status(next, message); };
|
|
14
|
+
const owner = { getStatus: () => ({ state, ...(diagnostic ? { diagnostic } : {}) }), dispose };
|
|
15
|
+
owners.set(key, owner);
|
|
16
|
+
publish('preparing');
|
|
17
|
+
const task = Promise.resolve().then(async () => {
|
|
18
|
+
releaseLease = await lease(connection.native.env.MCP_REMOTE_CONFIG_DIR);
|
|
19
|
+
if (controller.signal.aborted) return;
|
|
20
|
+
const checking = Date.now();
|
|
21
|
+
await checkPort(connection.native.args);
|
|
22
|
+
if (controller.signal.aborted) return;
|
|
23
|
+
let remaining = automaticMs - (Date.now() - checking);
|
|
24
|
+
for (let attempt = 0; ; attempt++) {
|
|
25
|
+
const attemptStarted = Date.now();
|
|
26
|
+
try {
|
|
27
|
+
const result = await authorizeClient(connection, { signal: controller.signal, status: publish, automaticMs: Math.max(1, remaining) });
|
|
28
|
+
remaining -= result?.automaticMsUsed ?? Date.now() - attemptStarted;
|
|
29
|
+
break;
|
|
30
|
+
} catch (error) {
|
|
31
|
+
remaining -= Date.now() - attemptStarted;
|
|
32
|
+
const pause = [2000, 5000][attempt];
|
|
33
|
+
if (controller.signal.aborted || !error.transient || attempt === 2 || remaining <= pause) throw error;
|
|
34
|
+
await wait(pause, undefined, { signal: controller.signal });
|
|
35
|
+
remaining -= pause;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (controller.signal.aborted) return;
|
|
39
|
+
if (remaining <= 0) throw new Error('Fotor automatic connection budget exceeded');
|
|
40
|
+
child = mount(connection.native);
|
|
41
|
+
// Disposal is registered before awaiting the native handshake.
|
|
42
|
+
let timer;
|
|
43
|
+
try {
|
|
44
|
+
await Promise.race([child.await(), new Promise((_, reject) => {
|
|
45
|
+
timer = setTimeout(() => reject(new Error('Fotor automatic connection budget exceeded')), Math.max(1, remaining));
|
|
46
|
+
})]);
|
|
47
|
+
} finally { clearTimeout(timer); }
|
|
48
|
+
if (!controller.signal.aborted) publish('connected');
|
|
49
|
+
}).catch(async error => {
|
|
50
|
+
if (!controller.signal.aborted) publish('failed', error.message);
|
|
51
|
+
if (child) await child.dispose();
|
|
52
|
+
});
|
|
53
|
+
let disposed;
|
|
54
|
+
function dispose() {
|
|
55
|
+
return disposed ??= (async () => {
|
|
56
|
+
controller.abort();
|
|
57
|
+
if (child) await child.dispose();
|
|
58
|
+
await task;
|
|
59
|
+
await releaseLease?.();
|
|
60
|
+
if (owners.get(key) === owner) owners.delete(key);
|
|
61
|
+
publish('stopped');
|
|
62
|
+
})();
|
|
63
|
+
}
|
|
64
|
+
return owner;
|
|
65
|
+
}
|
package/runtime/mcp.mjs
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** Auto-configure the host MCP client and own its cancellable authorization stage. */
|
|
2
|
+
import z from '@deepseek-ai/schemastery';
|
|
3
|
+
import { resolveMcp } from './config.mjs';
|
|
4
|
+
import { startConnection } from './lifecycle.mjs';
|
|
5
|
+
export const name = 'fotor-mcp';
|
|
6
|
+
export const inject = ['profileContext', 'tools'];
|
|
7
|
+
export const Config = z.object({
|
|
8
|
+
transport: z.const('stdio'), serverName: z.string(), command: z.string(),
|
|
9
|
+
args: z.union([z.const(undefined), z.array(z.string())]), env: z.dict(String), cwd: z.string(),
|
|
10
|
+
toolCallTimeoutMs: z.number().min(1), failOnStartupError: z.boolean(),
|
|
11
|
+
maxInstructionBytes: z.natural().min(1), endpoint: z.string(),
|
|
12
|
+
callbackPort: z.natural().min(1).max(65535),
|
|
13
|
+
reconnect: z.union([z.const(undefined), z.object({ enabled: z.const(false), initialDelayMs: z.number(), maxDelayMs: z.number(), maxAttempts: z.number() })]),
|
|
14
|
+
});
|
|
15
|
+
export async function apply(ctx, input = {}) {
|
|
16
|
+
const connection = await resolveMcp(input, { profileDir: ctx.profileContext.dir, cwd: ctx.profileContext.cwd });
|
|
17
|
+
const prefix = 'mcp__' + connection.native.serverName + '__';
|
|
18
|
+
if (ctx.get('fotorConnection') || ctx.tools.schemas().some(tool => tool.name.startsWith(prefix))) throw new Error('Fotor MCP service already registered');
|
|
19
|
+
const native = await import('@deepseek-ai/dsh-mcp-client');
|
|
20
|
+
const owner = startConnection(connection, {
|
|
21
|
+
mount: config => {
|
|
22
|
+
const prefix = 'mcp__' + config.serverName + '__';
|
|
23
|
+
if (ctx.tools.schemas().some(tool => tool.name.startsWith(prefix))) throw new Error('Fotor MCP service already registered');
|
|
24
|
+
const child = ctx.plugin(native, config);
|
|
25
|
+
return { dispose: () => child.dispose(), await: async () => {
|
|
26
|
+
await child.await();
|
|
27
|
+
if (!ctx.tools.schemas().some(tool => tool.name.startsWith(prefix))) throw new Error('Fotor MCP did not discover tools');
|
|
28
|
+
} };
|
|
29
|
+
},
|
|
30
|
+
status: (state, diagnostic) => ctx.logger.info('Fotor MCP: %s%s', state, diagnostic ? ' — ' + diagnostic : ''),
|
|
31
|
+
});
|
|
32
|
+
ctx.effect(() => () => owner.dispose(), 'fotor connection and callback cleanup');
|
|
33
|
+
ctx.provide('fotorConnection', owner);
|
|
34
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Adapt the native filesystem provider to this installed package. */
|
|
2
|
+
import z from '@deepseek-ai/schemastery';
|
|
3
|
+
import { resolveSkills } from './config.mjs';
|
|
4
|
+
export const name = 'fotor-skills';
|
|
5
|
+
export const inject = ['skills'];
|
|
6
|
+
export const Config = z.object({
|
|
7
|
+
providerName: z.string(), includeDefaultRoots: z.const(false),
|
|
8
|
+
customSkillDirs: z.union([z.const(undefined), z.array(z.string())]), watch: z.boolean(),
|
|
9
|
+
dshHome: z.string(), agentsHome: z.string(),
|
|
10
|
+
});
|
|
11
|
+
export async function apply(ctx, input = {}) {
|
|
12
|
+
if (ctx.get('fotorSkills')) throw new Error('Fotor skill provider already registered');
|
|
13
|
+
const config = await resolveSkills(input);
|
|
14
|
+
ctx.provide('fotorSkills', { root: config.customSkillDirs[0] });
|
|
15
|
+
const native = await import('@deepseek-ai/dsh-skill-filesystem');
|
|
16
|
+
const child = ctx.plugin(native, config);
|
|
17
|
+
ctx.effect(() => () => child.dispose(), 'fotor skill provider');
|
|
18
|
+
await child.await();
|
|
19
|
+
}
|
|
@@ -8,41 +8,29 @@ DeepSeek Harness is abbreviated as `dsh` in commands and native identifiers.
|
|
|
8
8
|
|
|
9
9
|
## Ownership and baseline
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
The current acceptance baseline is Linux DeepSeek Harness Web `0.2.1-rc.3`, with package-manager-owned `mcp-remote 0.15.2` and stable Node `>=24.2.0 <25.0.0 || 26.x`. Historical rc.2 results retain their original scope; matching the declared host range alone is not acceptance. DeepSeek Harness owns the stdio client and tool permissions; the bridge owns OAuth and its credential store. Do not describe this as native remote OAuth in DeepSeek Harness. Desktop, headless and ACP have separate acceptance scopes.
|
|
12
12
|
|
|
13
13
|
Use this guide with the [shared runtime workflow](mcp-integration.md#runtime-workflow). Installation, authorization, actual calls, website access, restart reuse and reauthorization recovery are distinct outcomes. Do not infer full support from one successful call.
|
|
14
14
|
|
|
15
|
-
##
|
|
15
|
+
## Installation and automatic configuration
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
For installation, source changes, missing dependencies, or invalid saved paths, read the installed package README and `INSTALL.md`. GitHub installation obtains the pinned bridge through the package manager; npm carries its full dependency tree. Node remains external.
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
From 0.6.1, select the installed Bundle with Web **Enable now** or load its CLI profile. Host activation enables both adapters by default. `fotor-skills` resolves this package's skills and uses the native filesystem provider without default-root scanning. `fotor-mcp` resolves Node and both installed bridge entrypoints, then supplies complete native stdio configuration. Runtime defaults are not written into a user patch. A package download alone runs no hook or authorization.
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Explicit profile/home/launch overrides, including disabled states and the external `MCP_REMOTE_CONFIG_DIR`, take precedence. Do not replace them or clear credentials to repair a path error. An obsolete path requires a targeted native configuration edit: remove only that override to adopt automatic resolution, or correct it. Conflicting Fotor services or skill providers require resolving the duplicate while preserving the existing installation.
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
Enable only the skill provider first. Use `/fotor-connect` when exposed by the native skill menu, or the native `skill` tool for the actual discovered Fotor connection entry. Confirm its installed resource path. Missing skills, a missing executable, a disabled component, permission denial, unauthenticated MCP and unknown state require different responses; none justifies clearing credentials.
|
|
26
|
-
|
|
27
|
-
Use DeepSeek Harness's native `read` tool for the known package references. Its Linux shell sandbox can hide other host files under a private temporary-directory mount; shell `ls` failure is not proof that native file reading will fail. If the native reader cannot access this package, report that limit and stop. Do not scan unrelated installations, use another platform's guide, or widen standing sandbox permissions to work around the lookup.
|
|
23
|
+
Use native `root`, `list` and `why` for diagnostics; do not guess pnpm store paths. The skill provider's running state alone is not discovery: verify the actual Fotor entries and their installed resource paths. Use native `read` for skill references; the Linux Shell sandbox can hide host paths. Do not scan unrelated packages after a native read failure.
|
|
28
24
|
|
|
29
25
|
## First authorization
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
Confirm the actual opener in this launch environment uses the user's daily ordinary browser. A task-specific desktop routing override may be needed; do not change the system default, create an incognito or headless session, or clear browser data. The model-provider login is independent of Fotor OAuth.
|
|
34
|
-
|
|
35
|
-
Run the installed dependency's native client entrypoint, using the same endpoint, resource, callback port/host and credential directory configured for the proxy:
|
|
27
|
+
Enabling MCP starts one cancellable connection task. The adapter runs the installed mcp-remote client with the same credential directory, endpoint, resource, callback and security arguments as the proxy. The bridge reuses valid credentials or opens the ordinary browser for user login and consent. Fotor code does not read tokens, implement OAuth, or install dependencies during connection. Model-provider login is separate.
|
|
36
28
|
|
|
37
|
-
|
|
29
|
+
Confirm the opener uses the user's daily ordinary browser; retain its profile and login state. A task-specific routing override may be used without changing the system default; record it separately from untouched default-browser behavior. Human authorization still belongs to the user, including Continue / Wait / Cancel. The adapter's states and sanitized diagnostics distinguish `preparing`, `waiting-authorization`, `connected`, `failed` and `stopped`; an active adapter is not proof of a connected MCP service.
|
|
38
30
|
|
|
39
|
-
|
|
40
|
-
MCP_REMOTE_CONFIG_DIR=/absolute/path/to/dsh-home/mcp-auth/fotor /absolute/path/to/node /absolute/path/from/dependency-query/mcp-remote/dist/client.js https://mcp.fotor.com/mcp <callback-port> --host <callback-host> --transport http-only --resource https://mcp.fotor.com/mcp --auth-timeout 600 --connect-timeout 20 --headers-timeout 20 --body-timeout 20
|
|
41
|
-
```
|
|
31
|
+
After Continue, require successful client connection and actual tools discovery. The client and callback listener must exit before the native MCP client starts the proxy. Proxy tool discovery completes readiness; a consent success page or zero client exit alone is insufficient. Authorization waits at most ten minutes. Cancel by disabling `fotor-mcp` through the native plugin controls; the owned child and callback must stop without blocking the Web interface. A cancelled or failed task waits for a deliberate disable/enable before another authorization attempt.
|
|
42
32
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
After the standalone client exits and its callback listener closes, enable the configured MCP component and restart the selected DeepSeek Harness profile. Discover actual tools and execute a read-only `list_models` check. Do not expose the whole model catalog, query credits or request a website link for an MCP-only task.
|
|
33
|
+
After connection, use `/fotor-connect` or the native skill tool for the actual discovered entry. Verify with a read-only `list_models` call when requested. MCP-only requests neither request a website link nor query credits. Installation, authorization, discovery and actual queries are distinct evidence.
|
|
46
34
|
|
|
47
35
|
## Website access
|
|
48
36
|
|
|
@@ -64,13 +52,17 @@ For user-requested reauthorization, use this single sequence:
|
|
|
64
52
|
|
|
65
53
|
1. Stop the failed operation, this profile's proxy and any leftover callback listener. Do not start a competing authorization flow.
|
|
66
54
|
2. Preserve the same credential directory and connection/security arguments. Do not read, copy or edit tokens.
|
|
67
|
-
3.
|
|
55
|
+
3. Re-enable the MCP adapter after the user requests another connection attempt. It runs the standalone authorization client and applies the same Continue / Wait / Cancel handling and native-result verification.
|
|
68
56
|
4. Stop the standalone client, restart the configured DeepSeek Harness MCP and prove recovery with an actual read-only query. A successful consent page without that query is not recovery.
|
|
69
57
|
|
|
70
|
-
A cached client connection without a new consent flow is reuse, not invalid-grant recovery. Never clear a global authorization directory, substitute a new empty store, weaken issuer/resource/PKCE/TLS checks or sign out the daily website to force a test.
|
|
58
|
+
A cached client connection without a new consent flow is reuse, not invalid-grant recovery. Never clear a global authorization directory, substitute a new empty store, weaken issuer/resource/PKCE/TLS checks or sign out the daily website to force a test. Server-side invalid-grant acceptance requires a real failure or an available native operation limited to this exact temporary grant. If no safe trigger exists, report that recovery scope as unverified. Expiry-driven refresh likewise requires actual evidence.
|
|
59
|
+
|
|
60
|
+
An explicitly user-approved isolated local-cache-loss test is a separate acceptance scope. After stopping all task-owned processes and callbacks, verify ownership and ordinary-file type before removing only that connection's token cache, without reading its contents. Keep the original directory, registration and connection parameters. Re-enable the adapter for user consent, then require an actual query and another query after a full restart. Label this local credential-loss recovery; it does not establish server-side revocation, expiry or intact rejected-cache recovery.
|
|
71
61
|
|
|
72
62
|
## Updating and removing
|
|
73
63
|
|
|
74
64
|
Use the native Bundle commands in the package README. After updating, inspect the resolved source, version, file contents and actual skill directory; package-manager links outside the package are distinct from forbidden symlinks inside its resources. Keep only one enabled Fotor skill source. Re-resolve the managed bridge path when replacing a package; preserve the external credential store.
|
|
75
65
|
|
|
76
|
-
Disable
|
|
66
|
+
Disable this Bundle before native removal. Retain its external overrides and credentials unless the user explicitly requests a targeted removal. Cleanup of an isolated acceptance environment may delete that environment's local store after all related processes stop; that does not revoke server-side consent. Leave daily installations, credentials and browser login unchanged. Keep package, model-session, bridge, website, reuse and recovery evidence separate.
|
|
67
|
+
|
|
68
|
+
Reinstalling the same source/profile with the same credential directory can reuse accepted authorization. It still establishes a new connection, so verify actual discovery and a requested read-only query. Changing profile, home, credential directory or connection parameters can select another cache. Preserve explicit disabled settings and valid complete configuration when upgrading; correct only obsolete path overrides through native configuration.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Connection
|
|
4
4
|
|
|
5
|
-
This **
|
|
5
|
+
This **test release channel** package connects to the **production service** at `https://mcp.fotor.com/mcp` using Streamable HTTP. Both release channels use the production account, website, and credits. Preserve this service throughout a task and its assets.
|
|
6
6
|
|
|
7
7
|
| Environment | MCP endpoint | Website target | Login handoff endpoint |
|
|
8
8
|
| --- | --- | --- | --- |
|
|
@@ -8,41 +8,29 @@ DeepSeek Harness is abbreviated as `dsh` in commands and native identifiers.
|
|
|
8
8
|
|
|
9
9
|
## Ownership and baseline
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
The current acceptance baseline is Linux DeepSeek Harness Web `0.2.1-rc.3`, with package-manager-owned `mcp-remote 0.15.2` and stable Node `>=24.2.0 <25.0.0 || 26.x`. Historical rc.2 results retain their original scope; matching the declared host range alone is not acceptance. DeepSeek Harness owns the stdio client and tool permissions; the bridge owns OAuth and its credential store. Do not describe this as native remote OAuth in DeepSeek Harness. Desktop, headless and ACP have separate acceptance scopes.
|
|
12
12
|
|
|
13
13
|
Use this guide with the [shared runtime workflow](mcp-integration.md#runtime-workflow). Installation, authorization, actual calls, website access, restart reuse and reauthorization recovery are distinct outcomes. Do not infer full support from one successful call.
|
|
14
14
|
|
|
15
|
-
##
|
|
15
|
+
## Installation and automatic configuration
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
For installation, source changes, missing dependencies, or invalid saved paths, read the installed package README and `INSTALL.md`. GitHub installation obtains the pinned bridge through the package manager; npm carries its full dependency tree. Node remains external.
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
From 0.6.1, select the installed Bundle with Web **Enable now** or load its CLI profile. Host activation enables both adapters by default. `fotor-skills` resolves this package's skills and uses the native filesystem provider without default-root scanning. `fotor-mcp` resolves Node and both installed bridge entrypoints, then supplies complete native stdio configuration. Runtime defaults are not written into a user patch. A package download alone runs no hook or authorization.
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Explicit profile/home/launch overrides, including disabled states and the external `MCP_REMOTE_CONFIG_DIR`, take precedence. Do not replace them or clear credentials to repair a path error. An obsolete path requires a targeted native configuration edit: remove only that override to adopt automatic resolution, or correct it. Conflicting Fotor services or skill providers require resolving the duplicate while preserving the existing installation.
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
Enable only the skill provider first. Use `/fotor-connect` when exposed by the native skill menu, or the native `skill` tool for the actual discovered Fotor connection entry. Confirm its installed resource path. Missing skills, a missing executable, a disabled component, permission denial, unauthenticated MCP and unknown state require different responses; none justifies clearing credentials.
|
|
26
|
-
|
|
27
|
-
Use DeepSeek Harness's native `read` tool for the known package references. Its Linux shell sandbox can hide other host files under a private temporary-directory mount; shell `ls` failure is not proof that native file reading will fail. If the native reader cannot access this package, report that limit and stop. Do not scan unrelated installations, use another platform's guide, or widen standing sandbox permissions to work around the lookup.
|
|
23
|
+
Use native `root`, `list` and `why` for diagnostics; do not guess pnpm store paths. The skill provider's running state alone is not discovery: verify the actual Fotor entries and their installed resource paths. Use native `read` for skill references; the Linux Shell sandbox can hide host paths. Do not scan unrelated packages after a native read failure.
|
|
28
24
|
|
|
29
25
|
## First authorization
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
Confirm the actual opener in this launch environment uses the user's daily ordinary browser. A task-specific desktop routing override may be needed; do not change the system default, create an incognito or headless session, or clear browser data. The model-provider login is independent of Fotor OAuth.
|
|
34
|
-
|
|
35
|
-
Run the installed dependency's native client entrypoint, using the same endpoint, resource, callback port/host and credential directory configured for the proxy:
|
|
27
|
+
Enabling MCP starts one cancellable connection task. The adapter runs the installed mcp-remote client with the same credential directory, endpoint, resource, callback and security arguments as the proxy. The bridge reuses valid credentials or opens the ordinary browser for user login and consent. Fotor code does not read tokens, implement OAuth, or install dependencies during connection. Model-provider login is separate.
|
|
36
28
|
|
|
37
|
-
|
|
29
|
+
Confirm the opener uses the user's daily ordinary browser; retain its profile and login state. A task-specific routing override may be used without changing the system default; record it separately from untouched default-browser behavior. Human authorization still belongs to the user, including Continue / Wait / Cancel. The adapter's states and sanitized diagnostics distinguish `preparing`, `waiting-authorization`, `connected`, `failed` and `stopped`; an active adapter is not proof of a connected MCP service.
|
|
38
30
|
|
|
39
|
-
|
|
40
|
-
MCP_REMOTE_CONFIG_DIR=/absolute/path/to/dsh-home/mcp-auth/fotor /absolute/path/to/node /absolute/path/from/dependency-query/mcp-remote/dist/client.js https://mcp.fotor.com/mcp <callback-port> --host <callback-host> --transport http-only --resource https://mcp.fotor.com/mcp --auth-timeout 600 --connect-timeout 20 --headers-timeout 20 --body-timeout 20
|
|
41
|
-
```
|
|
31
|
+
After Continue, require successful client connection and actual tools discovery. The client and callback listener must exit before the native MCP client starts the proxy. Proxy tool discovery completes readiness; a consent success page or zero client exit alone is insufficient. Authorization waits at most ten minutes. Cancel by disabling `fotor-mcp` through the native plugin controls; the owned child and callback must stop without blocking the Web interface. A cancelled or failed task waits for a deliberate disable/enable before another authorization attempt.
|
|
42
32
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
After the standalone client exits and its callback listener closes, enable the configured MCP component and restart the selected DeepSeek Harness profile. Discover actual tools and execute a read-only `list_models` check. Do not expose the whole model catalog, query credits or request a website link for an MCP-only task.
|
|
33
|
+
After connection, use `/fotor-connect` or the native skill tool for the actual discovered entry. Verify with a read-only `list_models` call when requested. MCP-only requests neither request a website link nor query credits. Installation, authorization, discovery and actual queries are distinct evidence.
|
|
46
34
|
|
|
47
35
|
## Website access
|
|
48
36
|
|
|
@@ -64,13 +52,17 @@ For user-requested reauthorization, use this single sequence:
|
|
|
64
52
|
|
|
65
53
|
1. Stop the failed operation, this profile's proxy and any leftover callback listener. Do not start a competing authorization flow.
|
|
66
54
|
2. Preserve the same credential directory and connection/security arguments. Do not read, copy or edit tokens.
|
|
67
|
-
3.
|
|
55
|
+
3. Re-enable the MCP adapter after the user requests another connection attempt. It runs the standalone authorization client and applies the same Continue / Wait / Cancel handling and native-result verification.
|
|
68
56
|
4. Stop the standalone client, restart the configured DeepSeek Harness MCP and prove recovery with an actual read-only query. A successful consent page without that query is not recovery.
|
|
69
57
|
|
|
70
|
-
A cached client connection without a new consent flow is reuse, not invalid-grant recovery. Never clear a global authorization directory, substitute a new empty store, weaken issuer/resource/PKCE/TLS checks or sign out the daily website to force a test.
|
|
58
|
+
A cached client connection without a new consent flow is reuse, not invalid-grant recovery. Never clear a global authorization directory, substitute a new empty store, weaken issuer/resource/PKCE/TLS checks or sign out the daily website to force a test. Server-side invalid-grant acceptance requires a real failure or an available native operation limited to this exact temporary grant. If no safe trigger exists, report that recovery scope as unverified. Expiry-driven refresh likewise requires actual evidence.
|
|
59
|
+
|
|
60
|
+
An explicitly user-approved isolated local-cache-loss test is a separate acceptance scope. After stopping all task-owned processes and callbacks, verify ownership and ordinary-file type before removing only that connection's token cache, without reading its contents. Keep the original directory, registration and connection parameters. Re-enable the adapter for user consent, then require an actual query and another query after a full restart. Label this local credential-loss recovery; it does not establish server-side revocation, expiry or intact rejected-cache recovery.
|
|
71
61
|
|
|
72
62
|
## Updating and removing
|
|
73
63
|
|
|
74
64
|
Use the native Bundle commands in the package README. After updating, inspect the resolved source, version, file contents and actual skill directory; package-manager links outside the package are distinct from forbidden symlinks inside its resources. Keep only one enabled Fotor skill source. Re-resolve the managed bridge path when replacing a package; preserve the external credential store.
|
|
75
65
|
|
|
76
|
-
Disable
|
|
66
|
+
Disable this Bundle before native removal. Retain its external overrides and credentials unless the user explicitly requests a targeted removal. Cleanup of an isolated acceptance environment may delete that environment's local store after all related processes stop; that does not revoke server-side consent. Leave daily installations, credentials and browser login unchanged. Keep package, model-session, bridge, website, reuse and recovery evidence separate.
|
|
67
|
+
|
|
68
|
+
Reinstalling the same source/profile with the same credential directory can reuse accepted authorization. It still establishes a new connection, so verify actual discovery and a requested read-only query. Changing profile, home, credential directory or connection parameters can select another cache. Preserve explicit disabled settings and valid complete configuration when upgrading; correct only obsolete path overrides through native configuration.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Connection
|
|
4
4
|
|
|
5
|
-
This **
|
|
5
|
+
This **test release channel** package connects to the **production service** at `https://mcp.fotor.com/mcp` using Streamable HTTP. Both release channels use the production account, website, and credits. Preserve this service throughout a task and its assets.
|
|
6
6
|
|
|
7
7
|
| Environment | MCP endpoint | Website target | Login handoff endpoint |
|
|
8
8
|
| --- | --- | --- | --- |
|
|
@@ -8,41 +8,29 @@ DeepSeek Harness is abbreviated as `dsh` in commands and native identifiers.
|
|
|
8
8
|
|
|
9
9
|
## Ownership and baseline
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
The current acceptance baseline is Linux DeepSeek Harness Web `0.2.1-rc.3`, with package-manager-owned `mcp-remote 0.15.2` and stable Node `>=24.2.0 <25.0.0 || 26.x`. Historical rc.2 results retain their original scope; matching the declared host range alone is not acceptance. DeepSeek Harness owns the stdio client and tool permissions; the bridge owns OAuth and its credential store. Do not describe this as native remote OAuth in DeepSeek Harness. Desktop, headless and ACP have separate acceptance scopes.
|
|
12
12
|
|
|
13
13
|
Use this guide with the [shared runtime workflow](mcp-integration.md#runtime-workflow). Installation, authorization, actual calls, website access, restart reuse and reauthorization recovery are distinct outcomes. Do not infer full support from one successful call.
|
|
14
14
|
|
|
15
|
-
##
|
|
15
|
+
## Installation and automatic configuration
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
For installation, source changes, missing dependencies, or invalid saved paths, read the installed package README and `INSTALL.md`. GitHub installation obtains the pinned bridge through the package manager; npm carries its full dependency tree. Node remains external.
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
From 0.6.1, select the installed Bundle with Web **Enable now** or load its CLI profile. Host activation enables both adapters by default. `fotor-skills` resolves this package's skills and uses the native filesystem provider without default-root scanning. `fotor-mcp` resolves Node and both installed bridge entrypoints, then supplies complete native stdio configuration. Runtime defaults are not written into a user patch. A package download alone runs no hook or authorization.
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Explicit profile/home/launch overrides, including disabled states and the external `MCP_REMOTE_CONFIG_DIR`, take precedence. Do not replace them or clear credentials to repair a path error. An obsolete path requires a targeted native configuration edit: remove only that override to adopt automatic resolution, or correct it. Conflicting Fotor services or skill providers require resolving the duplicate while preserving the existing installation.
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
Enable only the skill provider first. Use `/fotor-connect` when exposed by the native skill menu, or the native `skill` tool for the actual discovered Fotor connection entry. Confirm its installed resource path. Missing skills, a missing executable, a disabled component, permission denial, unauthenticated MCP and unknown state require different responses; none justifies clearing credentials.
|
|
26
|
-
|
|
27
|
-
Use DeepSeek Harness's native `read` tool for the known package references. Its Linux shell sandbox can hide other host files under a private temporary-directory mount; shell `ls` failure is not proof that native file reading will fail. If the native reader cannot access this package, report that limit and stop. Do not scan unrelated installations, use another platform's guide, or widen standing sandbox permissions to work around the lookup.
|
|
23
|
+
Use native `root`, `list` and `why` for diagnostics; do not guess pnpm store paths. The skill provider's running state alone is not discovery: verify the actual Fotor entries and their installed resource paths. Use native `read` for skill references; the Linux Shell sandbox can hide host paths. Do not scan unrelated packages after a native read failure.
|
|
28
24
|
|
|
29
25
|
## First authorization
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
Confirm the actual opener in this launch environment uses the user's daily ordinary browser. A task-specific desktop routing override may be needed; do not change the system default, create an incognito or headless session, or clear browser data. The model-provider login is independent of Fotor OAuth.
|
|
34
|
-
|
|
35
|
-
Run the installed dependency's native client entrypoint, using the same endpoint, resource, callback port/host and credential directory configured for the proxy:
|
|
27
|
+
Enabling MCP starts one cancellable connection task. The adapter runs the installed mcp-remote client with the same credential directory, endpoint, resource, callback and security arguments as the proxy. The bridge reuses valid credentials or opens the ordinary browser for user login and consent. Fotor code does not read tokens, implement OAuth, or install dependencies during connection. Model-provider login is separate.
|
|
36
28
|
|
|
37
|
-
|
|
29
|
+
Confirm the opener uses the user's daily ordinary browser; retain its profile and login state. A task-specific routing override may be used without changing the system default; record it separately from untouched default-browser behavior. Human authorization still belongs to the user, including Continue / Wait / Cancel. The adapter's states and sanitized diagnostics distinguish `preparing`, `waiting-authorization`, `connected`, `failed` and `stopped`; an active adapter is not proof of a connected MCP service.
|
|
38
30
|
|
|
39
|
-
|
|
40
|
-
MCP_REMOTE_CONFIG_DIR=/absolute/path/to/dsh-home/mcp-auth/fotor /absolute/path/to/node /absolute/path/from/dependency-query/mcp-remote/dist/client.js https://mcp.fotor.com/mcp <callback-port> --host <callback-host> --transport http-only --resource https://mcp.fotor.com/mcp --auth-timeout 600 --connect-timeout 20 --headers-timeout 20 --body-timeout 20
|
|
41
|
-
```
|
|
31
|
+
After Continue, require successful client connection and actual tools discovery. The client and callback listener must exit before the native MCP client starts the proxy. Proxy tool discovery completes readiness; a consent success page or zero client exit alone is insufficient. Authorization waits at most ten minutes. Cancel by disabling `fotor-mcp` through the native plugin controls; the owned child and callback must stop without blocking the Web interface. A cancelled or failed task waits for a deliberate disable/enable before another authorization attempt.
|
|
42
32
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
After the standalone client exits and its callback listener closes, enable the configured MCP component and restart the selected DeepSeek Harness profile. Discover actual tools and execute a read-only `list_models` check. Do not expose the whole model catalog, query credits or request a website link for an MCP-only task.
|
|
33
|
+
After connection, use `/fotor-connect` or the native skill tool for the actual discovered entry. Verify with a read-only `list_models` call when requested. MCP-only requests neither request a website link nor query credits. Installation, authorization, discovery and actual queries are distinct evidence.
|
|
46
34
|
|
|
47
35
|
## Website access
|
|
48
36
|
|
|
@@ -64,13 +52,17 @@ For user-requested reauthorization, use this single sequence:
|
|
|
64
52
|
|
|
65
53
|
1. Stop the failed operation, this profile's proxy and any leftover callback listener. Do not start a competing authorization flow.
|
|
66
54
|
2. Preserve the same credential directory and connection/security arguments. Do not read, copy or edit tokens.
|
|
67
|
-
3.
|
|
55
|
+
3. Re-enable the MCP adapter after the user requests another connection attempt. It runs the standalone authorization client and applies the same Continue / Wait / Cancel handling and native-result verification.
|
|
68
56
|
4. Stop the standalone client, restart the configured DeepSeek Harness MCP and prove recovery with an actual read-only query. A successful consent page without that query is not recovery.
|
|
69
57
|
|
|
70
|
-
A cached client connection without a new consent flow is reuse, not invalid-grant recovery. Never clear a global authorization directory, substitute a new empty store, weaken issuer/resource/PKCE/TLS checks or sign out the daily website to force a test.
|
|
58
|
+
A cached client connection without a new consent flow is reuse, not invalid-grant recovery. Never clear a global authorization directory, substitute a new empty store, weaken issuer/resource/PKCE/TLS checks or sign out the daily website to force a test. Server-side invalid-grant acceptance requires a real failure or an available native operation limited to this exact temporary grant. If no safe trigger exists, report that recovery scope as unverified. Expiry-driven refresh likewise requires actual evidence.
|
|
59
|
+
|
|
60
|
+
An explicitly user-approved isolated local-cache-loss test is a separate acceptance scope. After stopping all task-owned processes and callbacks, verify ownership and ordinary-file type before removing only that connection's token cache, without reading its contents. Keep the original directory, registration and connection parameters. Re-enable the adapter for user consent, then require an actual query and another query after a full restart. Label this local credential-loss recovery; it does not establish server-side revocation, expiry or intact rejected-cache recovery.
|
|
71
61
|
|
|
72
62
|
## Updating and removing
|
|
73
63
|
|
|
74
64
|
Use the native Bundle commands in the package README. After updating, inspect the resolved source, version, file contents and actual skill directory; package-manager links outside the package are distinct from forbidden symlinks inside its resources. Keep only one enabled Fotor skill source. Re-resolve the managed bridge path when replacing a package; preserve the external credential store.
|
|
75
65
|
|
|
76
|
-
Disable
|
|
66
|
+
Disable this Bundle before native removal. Retain its external overrides and credentials unless the user explicitly requests a targeted removal. Cleanup of an isolated acceptance environment may delete that environment's local store after all related processes stop; that does not revoke server-side consent. Leave daily installations, credentials and browser login unchanged. Keep package, model-session, bridge, website, reuse and recovery evidence separate.
|
|
67
|
+
|
|
68
|
+
Reinstalling the same source/profile with the same credential directory can reuse accepted authorization. It still establishes a new connection, so verify actual discovery and a requested read-only query. Changing profile, home, credential directory or connection parameters can select another cache. Preserve explicit disabled settings and valid complete configuration when upgrading; correct only obsolete path overrides through native configuration.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Connection
|
|
4
4
|
|
|
5
|
-
This **
|
|
5
|
+
This **test release channel** package connects to the **production service** at `https://mcp.fotor.com/mcp` using Streamable HTTP. Both release channels use the production account, website, and credits. Preserve this service throughout a task and its assets.
|
|
6
6
|
|
|
7
7
|
| Environment | MCP endpoint | Website target | Login handoff endpoint |
|
|
8
8
|
| --- | --- | --- | --- |
|