@floomhq/floom-mcp-sync 1.0.4 → 1.0.6
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 +11 -5
- package/dist/lib/paths.js +14 -0
- package/dist/server.js +21 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,13 @@ Tiny MCP server for Floom skills. This package is part of the Floom Version 1 sy
|
|
|
6
6
|
npx -y @floomhq/floom-mcp-sync
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
On startup it reads `~/.floom/config.json`, fetches published, saved, and
|
|
9
|
+
On startup it reads `~/.floom/config.json`, fetches published, saved, and followed library skills, and writes missing files to the configured local skills directory. Account-backed sync requires `npx -y @floomhq/floom login`. Public and unlisted shared-link installs still work through `floom_install_skill` without an account. The background sync behavior is a Version 1 preview path.
|
|
10
|
+
|
|
11
|
+
Targets:
|
|
12
|
+
|
|
13
|
+
- default: Claude Code, `~/.claude/skills/`
|
|
14
|
+
- Codex: `FLOOM_TARGET=codex npx -y @floomhq/floom-mcp-sync`, `~/.codex/skills/`
|
|
15
|
+
- direct override: `FLOOM_SKILLS_DIR=/path/to/skills npx -y @floomhq/floom-mcp-sync`
|
|
10
16
|
|
|
11
17
|
Sync stores a machine-local manifest next to the Floom CLI config at `~/.floom/sync-manifest.json`.
|
|
12
18
|
Version 1 sync does not replace existing local Markdown files. Remote updates, existing untracked
|
|
@@ -22,15 +28,15 @@ Tools:
|
|
|
22
28
|
- `floom_search_skills(query, library?, type?, limit?)` searches `/api/v1/search` and returns compact skill hits with slug, title, description, library placement, folder, and install URL.
|
|
23
29
|
- `type`: `knowledge`, `instruction`, `workflow`, or `skill`
|
|
24
30
|
- `limit`: 1-50
|
|
25
|
-
- `floom_install_skill(slug)` fetches `/s/<slug>.md` and writes it locally.
|
|
26
|
-
- `floom_publish_skill(name, content, description?, visibility?, asset_type?, installs_as?, version?)` publishes Markdown through `/api/skills
|
|
31
|
+
- `floom_install_skill(slug)` fetches `/s/<slug>.md` and writes it locally. Public and unlisted skills do not require an account.
|
|
32
|
+
- `floom_publish_skill(name, content, description?, visibility?, asset_type?, installs_as?, version?)` publishes Markdown through `/api/skills` for the signed-in Floom account.
|
|
27
33
|
- `asset_type`: `knowledge`, `instruction`, `workflow`, or `skill` (default `skill`)
|
|
28
34
|
- `installs_as`: `claude_skill`, `memory`, `rule`, `codex_instruction`, `opencode_instruction`, `cursor_rule`, or `other` (default `claude_skill`)
|
|
29
35
|
- `version`: optional label like `1.0.0` or `v1-preview`
|
|
30
36
|
|
|
31
37
|
- `floom_list_libraries()` lists public Floom libraries.
|
|
32
|
-
- `floom_subscribe_library(slug)`
|
|
33
|
-
- `floom_unsubscribe_library(slug)`
|
|
38
|
+
- `floom_subscribe_library(slug)` follows a library for the signed-in user so the library syncs locally.
|
|
39
|
+
- `floom_unsubscribe_library(slug)` unfollows that library.
|
|
34
40
|
- `floom_move_skill(slug, folder, tags?)` sets the signed-in user's local folder/tags override.
|
|
35
41
|
|
|
36
42
|
Team workspaces, share invites, and role-based library access are planned for a later Floom version.
|
package/dist/lib/paths.js
CHANGED
|
@@ -4,7 +4,21 @@ import { assertValidSlug } from "./slug.js";
|
|
|
4
4
|
export function configPath() {
|
|
5
5
|
return process.env.FLOOM_CONFIG_PATH ?? join(homedir(), ".floom", "config.json");
|
|
6
6
|
}
|
|
7
|
+
export function agentTarget() {
|
|
8
|
+
const raw = (process.env.FLOOM_TARGET ?? process.env.FLOOM_AGENT_TARGET ?? "claude").toLowerCase();
|
|
9
|
+
if (raw === "codex")
|
|
10
|
+
return "codex";
|
|
11
|
+
if (raw === "claude")
|
|
12
|
+
return "claude";
|
|
13
|
+
throw new Error("Invalid FLOOM_TARGET. Use claude or codex.");
|
|
14
|
+
}
|
|
7
15
|
export function skillsDir() {
|
|
16
|
+
if (process.env.FLOOM_SKILLS_DIR)
|
|
17
|
+
return process.env.FLOOM_SKILLS_DIR;
|
|
18
|
+
if (agentTarget() === "codex") {
|
|
19
|
+
const codexHome = process.env.CODEX_HOME ?? join(homedir(), ".codex");
|
|
20
|
+
return process.env.CODEX_SKILLS_DIR ?? join(codexHome, "skills");
|
|
21
|
+
}
|
|
8
22
|
return process.env.CLAUDE_SKILLS_DIR ?? join(homedir(), ".claude", "skills");
|
|
9
23
|
}
|
|
10
24
|
export function skillPath(slug) {
|
package/dist/server.js
CHANGED
|
@@ -6,7 +6,8 @@ import { installSkill } from "./tools/install.js";
|
|
|
6
6
|
import { publishSkill } from "./tools/publish.js";
|
|
7
7
|
import { listLibraries, moveSkill, subscribeLibrary, unsubscribeLibrary, } from "./tools/libraries.js";
|
|
8
8
|
import { searchSkills } from "./tools/search.js";
|
|
9
|
-
|
|
9
|
+
import { agentTarget, skillsDir } from "./lib/paths.js";
|
|
10
|
+
const SERVER_VERSION = "1.0.6";
|
|
10
11
|
const DEFAULT_INTERVAL_MS = 60_000;
|
|
11
12
|
const MIN_INTERVAL_MS = 10_000;
|
|
12
13
|
const VERSION_RE = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,63}$/;
|
|
@@ -33,7 +34,9 @@ Usage
|
|
|
33
34
|
|
|
34
35
|
Behavior
|
|
35
36
|
Starts a stdio MCP server.
|
|
36
|
-
Syncs published, saved, and
|
|
37
|
+
Syncs published, saved, and followed library skills into the configured local skills directory.
|
|
38
|
+
Requires a signed-in Floom CLI account for account-backed sync.
|
|
39
|
+
Public and unlisted shared-link installs still work through floom_install_skill without an account.
|
|
37
40
|
Polls for updates while the MCP process is running.
|
|
38
41
|
|
|
39
42
|
Options
|
|
@@ -42,6 +45,10 @@ Options
|
|
|
42
45
|
|
|
43
46
|
Env
|
|
44
47
|
FLOOM_API_URL Override the API host.
|
|
48
|
+
FLOOM_TARGET claude or codex. Default: claude.
|
|
49
|
+
FLOOM_SKILLS_DIR Override the local skills directory directly.
|
|
50
|
+
CLAUDE_SKILLS_DIR Override Claude's skills directory.
|
|
51
|
+
CODEX_SKILLS_DIR Override Codex's skills directory.
|
|
45
52
|
FLOOM_SYNC_INTERVAL_MS Poll interval in milliseconds. Minimum: 10000.
|
|
46
53
|
`.trimStart();
|
|
47
54
|
}
|
|
@@ -96,7 +103,7 @@ function toolList() {
|
|
|
96
103
|
tools: [
|
|
97
104
|
{
|
|
98
105
|
name: "floom_search_skills",
|
|
99
|
-
description: "Search public Floom skills
|
|
106
|
+
description: "Search public Floom skills before recreating reusable behavior from scratch.",
|
|
100
107
|
inputSchema: {
|
|
101
108
|
type: "object",
|
|
102
109
|
properties: {
|
|
@@ -111,7 +118,7 @@ function toolList() {
|
|
|
111
118
|
},
|
|
112
119
|
{
|
|
113
120
|
name: "floom_install_skill",
|
|
114
|
-
description: "Fetch a Floom skill by slug and install it into
|
|
121
|
+
description: "Fetch a Floom skill by slug and install it into the configured local skills directory. Public and unlisted links do not require an account.",
|
|
115
122
|
inputSchema: {
|
|
116
123
|
type: "object",
|
|
117
124
|
properties: {
|
|
@@ -123,7 +130,7 @@ function toolList() {
|
|
|
123
130
|
},
|
|
124
131
|
{
|
|
125
132
|
name: "floom_publish_skill",
|
|
126
|
-
description: "Publish Markdown content to Floom as a skill.",
|
|
133
|
+
description: "Publish Markdown content to the signed-in Floom account as a skill. Requires CLI login/config.",
|
|
127
134
|
inputSchema: {
|
|
128
135
|
type: "object",
|
|
129
136
|
properties: {
|
|
@@ -150,7 +157,7 @@ function toolList() {
|
|
|
150
157
|
},
|
|
151
158
|
{
|
|
152
159
|
name: "floom_subscribe_library",
|
|
153
|
-
description: "
|
|
160
|
+
description: "Follow a Floom library for the signed-in user so its skills sync locally.",
|
|
154
161
|
inputSchema: {
|
|
155
162
|
type: "object",
|
|
156
163
|
properties: {
|
|
@@ -162,7 +169,7 @@ function toolList() {
|
|
|
162
169
|
},
|
|
163
170
|
{
|
|
164
171
|
name: "floom_unsubscribe_library",
|
|
165
|
-
description: "
|
|
172
|
+
description: "Unfollow a Floom library for the signed-in user.",
|
|
166
173
|
inputSchema: {
|
|
167
174
|
type: "object",
|
|
168
175
|
properties: {
|
|
@@ -319,7 +326,12 @@ async function handleRequest(message) {
|
|
|
319
326
|
stdout.write(response(id, {
|
|
320
327
|
protocolVersion: "2025-06-18",
|
|
321
328
|
capabilities: { tools: {} },
|
|
322
|
-
serverInfo: {
|
|
329
|
+
serverInfo: {
|
|
330
|
+
name: "floom-mcp-sync",
|
|
331
|
+
version: SERVER_VERSION,
|
|
332
|
+
target: agentTarget(),
|
|
333
|
+
skillsDir: skillsDir(),
|
|
334
|
+
},
|
|
323
335
|
}));
|
|
324
336
|
return;
|
|
325
337
|
}
|
|
@@ -345,7 +357,7 @@ async function main() {
|
|
|
345
357
|
if (handleCliArgs(process.argv.slice(2)))
|
|
346
358
|
return;
|
|
347
359
|
const intervalMs = resolvePollIntervalMs();
|
|
348
|
-
process.stderr.write(`[floom] starting sync poller (interval ${intervalMs}ms)\n`);
|
|
360
|
+
process.stderr.write(`[floom] starting sync poller for ${agentTarget()} at ${skillsDir()} (interval ${intervalMs}ms)\n`);
|
|
349
361
|
const syncState = { inFlight: true };
|
|
350
362
|
void autoSync().catch((err) => {
|
|
351
363
|
process.stderr.write(`[floom] initial sync failed: ${err instanceof Error ? err.message : String(err)}\n`);
|