Skip to content

feat: Add relative path and multi-platform support for Craft Agents Sources - #918

Open
rayliverified wants to merge 4 commits into
craft-ai-agents:mainfrom
rayliverified:feat/relative-resource-config-dirs
Open

feat: Add relative path and multi-platform support for Craft Agents Sources#918
rayliverified wants to merge 4 commits into
craft-ai-agents:mainfrom
rayliverified:feat/relative-resource-config-dirs

Conversation

@rayliverified

@rayliverified rayliverified commented Jun 24, 2026

Copy link
Copy Markdown

Summary

Adds path variable expansion and platform overrides for MCP stdio source configs, making them portable across machines and operating systems.

Builds on #851 (CONFIG_DIR centralization).

Problem

Source configs contain absolute paths and platform-specific commands that break when shared across machines or operating systems:

{
  "command": "/Users/ray/.crawl4ai/venv/bin/python",
  "args": ["/Users/ray/projects/crawl4ai/server/bin/main.py"],
  "env": { "PYTHONPATH": "/Users/ray/.crawl4ai/crawl4ai-mcp-server" }
}

After — cross-platform portable config:

{
  "command": "${HOME}/.crawl4ai/venv/bin/python",
  "args": ["${SOURCE_DIR}/server/bin/main.py"],
  "env": {
    "PYTHONPATH": "${HOME}/.crawl4ai/crawl4ai-mcp-server"
  },
  "platform": {
    "win32": {
      "command": "C:\\Users\\dev\\.crawl4ai\\venv\\Scripts\\python.exe"
    }
  }
}

This config works on macOS, Linux, and Windows without modification.


Path Variables API

Optional ${...} references expanded at runtime in command, args, and env values.

Supported Variables

Variable Resolves To Example
${HOME} User home directory ${HOME}/.local/bin/node
${CRAFT_CONFIG_DIR} Craft Agent config dir (~/.craft-agent) ${CRAFT_CONFIG_DIR}/sources/my-mcp/data
${WORKSPACE} Current workspace root path ${WORKSPACE}/shared-tools/server.js
${SOURCE_DIR} This source's own folder ${SOURCE_DIR}/server/index.js

Behavior

  • Variables expand only when ${...} syntax is present — bare strings like "true", "dart", "production" pass through unchanged
  • Expansion is runtime-only — the original config.json is never modified

Example

{
  "mcp": {
    "transport": "stdio",
    "command": "${HOME}/.venv/bin/python",
    "args": ["${SOURCE_DIR}/server/main.py"],
    "env": {
      "PYTHONPATH": "${HOME}/.local/lib",
      "DEBUG": "true"
    }
  }
}

Platform Overrides API

Optional per-OS overrides for command, args, and env. Keys are win32, darwin, and linux (matching Node.js process.platform).

Config Format

{
  "mcp": {
    "transport": "stdio",
    "command": "python",
    "args": ["${SOURCE_DIR}/server/main.py"],
    "env": { "LOG_LEVEL": "info" },
    "platform": {
      "win32": {
        "command": "string",
        "args": ["string"],
        "env": { "KEY": "value" }
      },
      "darwin": {
        "command": "string",
        "args": ["string"],
        "env": { "KEY": "value" }
      },
      "linux": {
        "command": "string",
        "args": ["string"],
        "env": { "KEY": "value" }
      }
    }
  }
}

Override Rules

Field Behavior
command Replaces the default command
args Replaces the default args entirely
env Merges on top of default env (platform keys add or overwrite; default keys not mentioned are preserved)

If a platform key is absent or a field is omitted from the override, the default value is used.

Example

{
  "command": "${HOME}/.crawl4ai/venv/bin/python",
  "args": ["${SOURCE_DIR}/server/main.py"],
  "env": {
    "PYTHONPATH": "${HOME}/.crawl4ai/crawl4ai-mcp-server",
    "LOG_LEVEL": "info"
  },
  "platform": {
    "win32": {
      "command": "C:\\Users\\dev\\.crawl4ai\\venv\\Scripts\\python.exe"
    },
    "darwin": {
      "args": ["${SOURCE_DIR}/server/main.py", "--verbose"],
      "env": { "LOG_LEVEL": "debug" }
    }
  }
}

Resolved on macOS (darwin):

  • command: "~/.crawl4ai/venv/bin/python" (default — no override)
  • args: [".../server/main.py", "--verbose"] (override replaces)
  • env: { PYTHONPATH: "...", LOG_LEVEL: "debug" } (override merges)

Resolved on Linux:

  • command: "~/.crawl4ai/venv/bin/python" (default)
  • args: [".../server/main.py"] (default)
  • env: { PYTHONPATH: "...", LOG_LEVEL: "info" } (default)

Resolved on Windows (win32):

  • command: "C:\\Users\\dev\\.crawl4ai\\venv\\Scripts\\python.exe" (override replaces)
  • args: ["...\\server\\main.py"] (default)
  • env: { PYTHONPATH: "...", LOG_LEVEL: "info" } (default)

Test Results

Feature Implemented Tested Result
${HOME} in command/args/env ✅ Pass
${SOURCE_DIR} in args ✅ Pass
${CRAFT_CONFIG_DIR} in env ✅ Pass
Variables not persisted after source_test ✅ Pass
Bare commands not coerced to absolute paths ✅ Pass
Non-path env values ("true") not coerced ✅ Pass
Platform overrides — command replaces ✅ Pass
Platform overrides — args replaces ✅ Pass
Platform overrides — env merges ✅ Pass
Platform blocks present but unused on current OS ✅ Pass
Config.json unchanged after all operations ✅ Pass

Changes

File Change
packages/shared/src/utils/paths.ts Add expandVars(), resolveStdioConfig(), PathVars interface
packages/shared/src/sources/types.ts Add platform field + McpPlatform/McpPlatformOverride types
packages/shared/src/sources/server-builder.ts Use resolveStdioConfig() at build time
packages/session-tools-core/src/handlers/source-test.ts Use resolveStdioConfig() for connection testing
apps/electron/resources/docs/sources.md Path Variables + Platform Overrides sections

Validation

  • cd packages/shared && bun run tsc --noEmit
  • cd packages/shared && bun test — 2891 pass, 0 fail
  • ✅ Manual end-to-end testing with live MCP server (crawl4ai-dart)

Co-Authored-By: Craft Agent agents-noreply@craft.do

rayliverified and others added 3 commits June 23, 2026 19:17
Extend expandPath() with optional extraVars parameter supporting
, , and  variables.
Apply expansion to MCP stdio fields (command, args, env values) at
load time in loadSourceConfig().

Existing configs with absolute paths work unchanged — expansion is
idempotent and variables are purely opt-in.

Builds on PR craft-ai-agents#851 (CONFIG_DIR centralization) which makes
 reliable as a single source of truth.

Co-Authored-By: Craft Agent <agents-noreply@craft.do>
Three bugs found during live testing:

1. Non-path env values treated as relative paths:
   expandPath() coerced bare strings like 'true' and 'dart' to
   absolute paths by resolving against cwd. Fixed by adding
   expandVars() which does variable substitution ONLY, leaving
   non-variable strings unchanged.

2. Expanded values persisted to config.json:
   Expansion at load time mutated the in-memory config object,
   which source_test then wrote back. Moved MCP field expansion
   from loadSourceConfig() to buildMcpServer() (runtime-only).

3. Bare command names treated as relative paths:
   'dart' became '/path/to/repo/dart'. Now uses expandVars()
   for command/args/env which leaves bare names as-is.

expandPath() now delegates to expandVars() for the variable
substitution step, then adds relative→absolute resolution on top.
expandPath() is still used for local source paths only.

Co-Authored-By: Craft Agent <agents-noreply@craft.do>
Adds a `platform` field to McpSourceConfig that allows overriding
command, args, and env per OS (win32, darwin, linux). This makes
source configs portable across different operating systems.

Override rules:
- command: replaces the default
- args: replaces the default entirely
- env: merges on top of the default (not replaced)

Resolution happens at runtime via resolveStdioConfig(), which also
handles path variable expansion. The original config.json is never
mutated — overrides and variable expansion are runtime-only.

Example:
{
  command: npx,
  platform: { win32: { command: npx.cmd } }
}

Co-Authored-By: Craft Agent <agents-noreply@craft.do>
@rayliverified rayliverified changed the title feat: add path variable expansion for MCP source configs feat: Add relative path and multi-platform support for Craft Agents Sources Jun 24, 2026
MCP stdio subprocesses now spawn with cwd set to the source's own
folder. This means relative paths in args (e.g. server/bin/main.dart)
resolve naturally without requiring ${SOURCE_DIR}/ prefixes.

Before:
  args: [${SOURCE_DIR}/server/bin/main.dart]

After (both work):
  args: [server/bin/main.dart]

Applies to:
- server-builder.ts: runtime server startup (buildMcpServer)
- source-test.ts: connection validation (validateStdioMcpConnection)
- validation.ts: StdioClientTransport now passes cwd

Co-Authored-By: Craft Agent <agents-noreply@craft.do>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant