crewly 1.20.246 → 1.20.248

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.
Files changed (72) hide show
  1. package/dist/backend/backend/src/constants.d.ts +31 -0
  2. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  3. package/dist/backend/backend/src/constants.js +31 -0
  4. package/dist/backend/backend/src/constants.js.map +1 -1
  5. package/dist/backend/backend/src/controllers/connector/connector.controller.d.ts +1 -0
  6. package/dist/backend/backend/src/controllers/connector/connector.controller.d.ts.map +1 -1
  7. package/dist/backend/backend/src/controllers/connector/connector.controller.js +7 -0
  8. package/dist/backend/backend/src/controllers/connector/connector.controller.js.map +1 -1
  9. package/dist/backend/backend/src/controllers/connector/connector.routes.d.ts +1 -0
  10. package/dist/backend/backend/src/controllers/connector/connector.routes.d.ts.map +1 -1
  11. package/dist/backend/backend/src/controllers/connector/connector.routes.js +7 -0
  12. package/dist/backend/backend/src/controllers/connector/connector.routes.js.map +1 -1
  13. package/dist/backend/backend/src/controllers/connector/remote-mcp.controller.d.ts +55 -0
  14. package/dist/backend/backend/src/controllers/connector/remote-mcp.controller.d.ts.map +1 -0
  15. package/dist/backend/backend/src/controllers/connector/remote-mcp.controller.js +148 -0
  16. package/dist/backend/backend/src/controllers/connector/remote-mcp.controller.js.map +1 -0
  17. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  18. package/dist/backend/backend/src/services/agent/agent-registration.service.js +5 -0
  19. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  20. package/dist/backend/backend/src/services/connector/connector-access.service.d.ts +8 -0
  21. package/dist/backend/backend/src/services/connector/connector-access.service.d.ts.map +1 -1
  22. package/dist/backend/backend/src/services/connector/connector-access.service.js +17 -0
  23. package/dist/backend/backend/src/services/connector/connector-access.service.js.map +1 -1
  24. package/dist/backend/backend/src/services/connector/remote-mcp-launch.service.d.ts +77 -0
  25. package/dist/backend/backend/src/services/connector/remote-mcp-launch.service.d.ts.map +1 -0
  26. package/dist/backend/backend/src/services/connector/remote-mcp-launch.service.js +132 -0
  27. package/dist/backend/backend/src/services/connector/remote-mcp-launch.service.js.map +1 -0
  28. package/dist/backend/backend/src/services/connector/remote-mcp-probe.service.d.ts +75 -0
  29. package/dist/backend/backend/src/services/connector/remote-mcp-probe.service.d.ts.map +1 -0
  30. package/dist/backend/backend/src/services/connector/remote-mcp-probe.service.js +155 -0
  31. package/dist/backend/backend/src/services/connector/remote-mcp-probe.service.js.map +1 -0
  32. package/dist/backend/backend/src/services/connector/remote-mcp.service.d.ts +192 -0
  33. package/dist/backend/backend/src/services/connector/remote-mcp.service.d.ts.map +1 -0
  34. package/dist/backend/backend/src/services/connector/remote-mcp.service.js +334 -0
  35. package/dist/backend/backend/src/services/connector/remote-mcp.service.js.map +1 -0
  36. package/dist/backend/backend/src/services/core/credential-files.d.ts.map +1 -1
  37. package/dist/backend/backend/src/services/core/credential-files.js +4 -1
  38. package/dist/backend/backend/src/services/core/credential-files.js.map +1 -1
  39. package/dist/backend/backend/src/services/worktree/docker-reclaim.d.ts +54 -0
  40. package/dist/backend/backend/src/services/worktree/docker-reclaim.d.ts.map +1 -0
  41. package/dist/backend/backend/src/services/worktree/docker-reclaim.js +102 -0
  42. package/dist/backend/backend/src/services/worktree/docker-reclaim.js.map +1 -0
  43. package/dist/backend/backend/src/services/worktree/worktree-janitor.service.d.ts +8 -0
  44. package/dist/backend/backend/src/services/worktree/worktree-janitor.service.d.ts.map +1 -1
  45. package/dist/backend/backend/src/services/worktree/worktree-janitor.service.js +23 -0
  46. package/dist/backend/backend/src/services/worktree/worktree-janitor.service.js.map +1 -1
  47. package/dist/backend/build-info.json +2 -2
  48. package/dist/cli/backend/src/constants.d.ts +31 -0
  49. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  50. package/dist/cli/backend/src/constants.js +31 -0
  51. package/dist/cli/backend/src/constants.js.map +1 -1
  52. package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  53. package/dist/cli/backend/src/services/agent/agent-registration.service.js +5 -0
  54. package/dist/cli/backend/src/services/agent/agent-registration.service.js.map +1 -1
  55. package/dist/cli/backend/src/services/connector/connector-access.service.d.ts +85 -0
  56. package/dist/cli/backend/src/services/connector/connector-access.service.d.ts.map +1 -0
  57. package/dist/cli/backend/src/services/connector/connector-access.service.js +130 -0
  58. package/dist/cli/backend/src/services/connector/connector-access.service.js.map +1 -0
  59. package/dist/cli/backend/src/services/connector/remote-mcp-launch.service.d.ts +77 -0
  60. package/dist/cli/backend/src/services/connector/remote-mcp-launch.service.d.ts.map +1 -0
  61. package/dist/cli/backend/src/services/connector/remote-mcp-launch.service.js +132 -0
  62. package/dist/cli/backend/src/services/connector/remote-mcp-launch.service.js.map +1 -0
  63. package/dist/cli/backend/src/services/connector/remote-mcp.service.d.ts +192 -0
  64. package/dist/cli/backend/src/services/connector/remote-mcp.service.d.ts.map +1 -0
  65. package/dist/cli/backend/src/services/connector/remote-mcp.service.js +334 -0
  66. package/dist/cli/backend/src/services/connector/remote-mcp.service.js.map +1 -0
  67. package/dist/cli/backend/src/services/core/credential-files.d.ts.map +1 -1
  68. package/dist/cli/backend/src/services/core/credential-files.js +4 -1
  69. package/dist/cli/backend/src/services/core/credential-files.js.map +1 -1
  70. package/frontend/dist/assets/{index-c9630c55.js → index-8f4d482e.js} +277 -277
  71. package/frontend/dist/index.html +1 -1
  72. package/package.json +1 -1
@@ -63,6 +63,14 @@ export declare class ConnectorAccessService {
63
63
  * @returns The stored rule
64
64
  */
65
65
  setAllowedRoles(connectorId: string, roles: string[]): Promise<ConnectorAccess>;
66
+ /**
67
+ * Drop a connector's rule (it goes back to open). Used when the connector
68
+ * itself is removed, so a later one with the same id starts open.
69
+ *
70
+ * @param connectorId - Connector id
71
+ * @returns True when a rule existed
72
+ */
73
+ removeRule(connectorId: string): Promise<boolean>;
66
74
  /**
67
75
  * Whether a caller may use a connector.
68
76
  *
@@ -1 +1 @@
1
- {"version":3,"file":"connector-access.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/connector/connector-access.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAOH,iCAAiC;AACjC,MAAM,WAAW,eAAe;IAC9B,oDAAoD;IACpD,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,2CAA2C;AAC3C,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAEjE,yEAAyE;AACzE,eAAO,MAAM,gBAAgB,0DAA2D,CAAC;AAEzF,uCAAuC;AACvC,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAKjE;;GAEG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAuC;IAC9D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,KAAK,CAAmC;IAEhD;;OAEG;gBACS,UAAU,CAAC,EAAE,MAAM;IAK/B,MAAM,CAAC,WAAW,IAAI,sBAAsB;IAK5C,mCAAmC;IACnC,MAAM,CAAC,aAAa,IAAI,IAAI;IAI5B;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAYzC;;;;;OAKG;IACG,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAI1D;;;;;;OAMG;IACG,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,CAAC;IAUrF;;;;;;OAMG;IACG,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IAOhF,wEAAwE;IACxE,UAAU,IAAI,IAAI;CAGnB"}
1
+ {"version":3,"file":"connector-access.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/connector/connector-access.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAOH,iCAAiC;AACjC,MAAM,WAAW,eAAe;IAC9B,oDAAoD;IACpD,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,2CAA2C;AAC3C,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAEjE,yEAAyE;AACzE,eAAO,MAAM,gBAAgB,0DAA2D,CAAC;AAEzF,uCAAuC;AACvC,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAKjE;;GAEG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAuC;IAC9D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,KAAK,CAAmC;IAEhD;;OAEG;gBACS,UAAU,CAAC,EAAE,MAAM;IAK/B,MAAM,CAAC,WAAW,IAAI,sBAAsB;IAK5C,mCAAmC;IACnC,MAAM,CAAC,aAAa,IAAI,IAAI;IAI5B;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAYzC;;;;;OAKG;IACG,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAI1D;;;;;;OAMG;IACG,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,CAAC;IAUrF;;;;;;OAMG;IACG,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUvD;;;;;;OAMG;IACG,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IAOhF,wEAAwE;IACxE,UAAU,IAAI,IAAI;CAGnB"}
@@ -90,6 +90,23 @@ export class ConnectorAccessService {
90
90
  this.logger.info('Connector access updated', { connectorId, allowedRoles: normalized });
91
91
  return map[connectorId];
92
92
  }
93
+ /**
94
+ * Drop a connector's rule (it goes back to open). Used when the connector
95
+ * itself is removed, so a later one with the same id starts open.
96
+ *
97
+ * @param connectorId - Connector id
98
+ * @returns True when a rule existed
99
+ */
100
+ async removeRule(connectorId) {
101
+ const map = { ...(await this.list()) };
102
+ if (!(connectorId in map))
103
+ return false;
104
+ delete map[connectorId];
105
+ await atomicWriteJson(this.filePath, map);
106
+ this.cache = map;
107
+ this.logger.info('Connector access rule removed', { connectorId });
108
+ return true;
109
+ }
93
110
  /**
94
111
  * Whether a caller may use a connector.
95
112
  *
@@ -1 +1 @@
1
- {"version":3,"file":"connector-access.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/connector/connector-access.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"connector-access.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/connector/connector-access.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Hand remote MCP servers to an agent at launch.
3
+ *
4
+ * For each server whose `mcp:<id>` allowlist admits the agent's role:
5
+ *
6
+ * | Runtime | How |
7
+ * |---|---|
8
+ * | Claude Code | `--mcp-config '<CREWLY_HOME>/runtime/remote-mcp/<session>/claude-mcp.json'` (adds to the project `.mcp.json`; no `--strict-mcp-config`) |
9
+ * | Codex | `-c "mcp_servers.<id>.url=$(cat '<file>')"` (+ `http_headers`), so the secret never appears on the typed command line |
10
+ * | Gemini CLI, Antigravity, OpenCode, crewly-agent | skipped with a log line |
11
+ *
12
+ * Every file is written under CREWLY_HOME with mode 0600 (directory 0700),
13
+ * never into the project. The returned flags carry only file paths.
14
+ *
15
+ * @module services/connector/remote-mcp-launch.service
16
+ */
17
+ import { RemoteMcpService, type RemoteMcpServer } from './remote-mcp.service.js';
18
+ /** Input for {@link buildRemoteMcpLaunchFlags}. */
19
+ export interface RemoteMcpLaunchInput {
20
+ /** PTY session name. */
21
+ sessionName: string;
22
+ /** Agent role (decides the allowlists). */
23
+ role: string;
24
+ /** Runtime being launched. */
25
+ runtimeType: string;
26
+ /** Override CREWLY_HOME (tests). */
27
+ crewlyHome?: string;
28
+ /** Override the store (tests). */
29
+ service?: RemoteMcpService;
30
+ }
31
+ /** What {@link buildRemoteMcpLaunchFlags} decided. */
32
+ export interface RemoteMcpLaunchResult {
33
+ /** Flags to add to the launch command (already shell-quoted). */
34
+ flags: string[];
35
+ /** Server ids handed to the agent. */
36
+ servers: string[];
37
+ /** Why nothing was added, when nothing was. */
38
+ skipped?: 'no-servers' | 'unsupported-runtime' | 'error';
39
+ }
40
+ /**
41
+ * The per-session directory for launch files.
42
+ *
43
+ * @param crewlyHome - CREWLY_HOME
44
+ * @param sessionName - PTY session name
45
+ * @returns Absolute directory
46
+ */
47
+ export declare function remoteMcpSessionDir(crewlyHome: string, sessionName: string): string;
48
+ /**
49
+ * Claude Code's `--mcp-config` body.
50
+ *
51
+ * @param servers - Allowed servers
52
+ * @returns `{ mcpServers: { <id>: { type: 'http', url, headers? } } }`
53
+ */
54
+ export declare function buildClaudeMcpConfig(servers: RemoteMcpServer[]): {
55
+ mcpServers: Record<string, {
56
+ type: 'http';
57
+ url: string;
58
+ headers?: Record<string, string>;
59
+ }>;
60
+ };
61
+ /**
62
+ * A TOML inline table of headers (JSON strings are valid TOML basic strings).
63
+ *
64
+ * @param headers - Header map
65
+ * @returns e.g. `{ "Authorization" = "Bearer x" }`
66
+ */
67
+ export declare function toTomlInlineTable(headers: Record<string, string>): string;
68
+ /**
69
+ * Write the launch files for one agent and return the flags that load them.
70
+ * Never throws: on any failure the agent launches without remote MCP and
71
+ * the error is logged (without secrets).
72
+ *
73
+ * @param input - Session, role, runtime
74
+ * @returns Flags and the server ids handed over
75
+ */
76
+ export declare function buildRemoteMcpLaunchFlags(input: RemoteMcpLaunchInput): Promise<RemoteMcpLaunchResult>;
77
+ //# sourceMappingURL=remote-mcp-launch.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-mcp-launch.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/connector/remote-mcp-launch.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAOH,OAAO,EAAE,gBAAgB,EAAmB,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAIlG,mDAAmD;AACnD,MAAM,WAAW,oBAAoB;IACnC,wBAAwB;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kCAAkC;IAClC,OAAO,CAAC,EAAE,gBAAgB,CAAC;CAC5B;AAED,sDAAsD;AACtD,MAAM,WAAW,qBAAqB;IACpC,iEAAiE;IACjE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,sCAAsC;IACtC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,+CAA+C;IAC/C,OAAO,CAAC,EAAE,YAAY,GAAG,qBAAqB,GAAG,OAAO,CAAC;CAC1D;AAYD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAGnF;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC,CAAA;CAAE,CAMhK;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAGzE;AAaD;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAgD3G"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Hand remote MCP servers to an agent at launch.
3
+ *
4
+ * For each server whose `mcp:<id>` allowlist admits the agent's role:
5
+ *
6
+ * | Runtime | How |
7
+ * |---|---|
8
+ * | Claude Code | `--mcp-config '<CREWLY_HOME>/runtime/remote-mcp/<session>/claude-mcp.json'` (adds to the project `.mcp.json`; no `--strict-mcp-config`) |
9
+ * | Codex | `-c "mcp_servers.<id>.url=$(cat '<file>')"` (+ `http_headers`), so the secret never appears on the typed command line |
10
+ * | Gemini CLI, Antigravity, OpenCode, crewly-agent | skipped with a log line |
11
+ *
12
+ * Every file is written under CREWLY_HOME with mode 0600 (directory 0700),
13
+ * never into the project. The returned flags carry only file paths.
14
+ *
15
+ * @module services/connector/remote-mcp-launch.service
16
+ */
17
+ import * as fs from 'fs/promises';
18
+ import * as path from 'path';
19
+ import { getCrewlyHomePath } from '../core/crewly-home.utils.js';
20
+ import { LoggerService } from '../core/logger.service.js';
21
+ import { REMOTE_MCP_CONSTANTS, RUNTIME_TYPES } from '../../constants.js';
22
+ import { RemoteMcpService, writeSecretJson } from './remote-mcp.service.js';
23
+ const C = REMOTE_MCP_CONSTANTS;
24
+ /**
25
+ * Quote for a POSIX shell.
26
+ *
27
+ * @param value - Raw value
28
+ * @returns Single-quoted value
29
+ */
30
+ function shq(value) {
31
+ return `'${value.replace(/'/g, `'\\''`)}'`;
32
+ }
33
+ /**
34
+ * The per-session directory for launch files.
35
+ *
36
+ * @param crewlyHome - CREWLY_HOME
37
+ * @param sessionName - PTY session name
38
+ * @returns Absolute directory
39
+ */
40
+ export function remoteMcpSessionDir(crewlyHome, sessionName) {
41
+ const safe = sessionName.replace(/[^A-Za-z0-9._-]/g, '_').replace(/^\.+/, '_') || '_';
42
+ return path.join(crewlyHome, C.RUNTIME_DIR, safe);
43
+ }
44
+ /**
45
+ * Claude Code's `--mcp-config` body.
46
+ *
47
+ * @param servers - Allowed servers
48
+ * @returns `{ mcpServers: { <id>: { type: 'http', url, headers? } } }`
49
+ */
50
+ export function buildClaudeMcpConfig(servers) {
51
+ const mcpServers = {};
52
+ for (const s of servers) {
53
+ mcpServers[s.id] = { type: 'http', url: s.url, ...(s.headers && Object.keys(s.headers).length ? { headers: s.headers } : {}) };
54
+ }
55
+ return { mcpServers };
56
+ }
57
+ /**
58
+ * A TOML inline table of headers (JSON strings are valid TOML basic strings).
59
+ *
60
+ * @param headers - Header map
61
+ * @returns e.g. `{ "Authorization" = "Bearer x" }`
62
+ */
63
+ export function toTomlInlineTable(headers) {
64
+ const parts = Object.entries(headers).map(([k, v]) => `${JSON.stringify(k)} = ${JSON.stringify(v)}`);
65
+ return `{ ${parts.join(', ')} }`;
66
+ }
67
+ /**
68
+ * Write a 0600 text file.
69
+ *
70
+ * @param file - Destination
71
+ * @param body - Content
72
+ */
73
+ async function writeSecretText(file, body) {
74
+ await fs.writeFile(file, body, { encoding: 'utf8', mode: 0o600 });
75
+ await fs.chmod(file, 0o600);
76
+ }
77
+ /**
78
+ * Write the launch files for one agent and return the flags that load them.
79
+ * Never throws: on any failure the agent launches without remote MCP and
80
+ * the error is logged (without secrets).
81
+ *
82
+ * @param input - Session, role, runtime
83
+ * @returns Flags and the server ids handed over
84
+ */
85
+ export async function buildRemoteMcpLaunchFlags(input) {
86
+ const logger = LoggerService.getInstance().createComponentLogger('RemoteMcpLaunch');
87
+ const { sessionName, role, runtimeType } = input;
88
+ const crewlyHome = input.crewlyHome || getCrewlyHomePath();
89
+ const dir = remoteMcpSessionDir(crewlyHome, sessionName);
90
+ try {
91
+ const servers = await (input.service ?? RemoteMcpService.getInstance()).serversForRole(role);
92
+ // Start clean: a server removed or a role narrowed since the last launch must be gone.
93
+ await fs.rm(dir, { recursive: true, force: true });
94
+ if (servers.length === 0)
95
+ return { flags: [], servers: [], skipped: 'no-servers' };
96
+ const ids = servers.map((s) => s.id);
97
+ if (runtimeType !== RUNTIME_TYPES.CLAUDE_CODE && runtimeType !== RUNTIME_TYPES.CODEX_CLI) {
98
+ logger.info('Remote MCP servers: not supported for this runtime — skipped', { sessionName, runtimeType, servers: ids });
99
+ return { flags: [], servers: [], skipped: 'unsupported-runtime' };
100
+ }
101
+ await fs.mkdir(dir, { recursive: true, mode: 0o700 });
102
+ await fs.chmod(dir, 0o700);
103
+ if (runtimeType === RUNTIME_TYPES.CLAUDE_CODE) {
104
+ const file = path.join(dir, C.CLAUDE_CONFIG_FILE);
105
+ await writeSecretJson(file, buildClaudeMcpConfig(servers));
106
+ logger.info('Remote MCP servers: added via --mcp-config', { sessionName, role, servers: ids });
107
+ return { flags: ['--mcp-config', shq(file)], servers: ids };
108
+ }
109
+ const flags = [];
110
+ for (const s of servers) {
111
+ const urlFile = path.join(dir, `codex-${s.id}-url.toml`);
112
+ await writeSecretText(urlFile, JSON.stringify(s.url));
113
+ flags.push('-c', `"mcp_servers.${s.id}.url=$(cat ${shq(urlFile)})"`);
114
+ if (s.headers && Object.keys(s.headers).length > 0) {
115
+ const headersFile = path.join(dir, `codex-${s.id}-headers.toml`);
116
+ await writeSecretText(headersFile, toTomlInlineTable(s.headers));
117
+ flags.push('-c', `"mcp_servers.${s.id}.http_headers=$(cat ${shq(headersFile)})"`);
118
+ }
119
+ }
120
+ logger.info('Remote MCP servers: added via codex -c mcp_servers', { sessionName, role, servers: ids });
121
+ return { flags, servers: ids };
122
+ }
123
+ catch (err) {
124
+ logger.error('Remote MCP servers: could not prepare launch files — launching without them', {
125
+ sessionName,
126
+ runtimeType,
127
+ error: err instanceof Error ? err.message : String(err),
128
+ });
129
+ return { flags: [], servers: [], skipped: 'error' };
130
+ }
131
+ }
132
+ //# sourceMappingURL=remote-mcp-launch.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-mcp-launch.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/connector/remote-mcp-launch.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * "Test" for a remote MCP server: MCP `initialize`, `notifications/initialized`
3
+ * and `tools/list` over streamable HTTP, reporting the tool count and names.
4
+ *
5
+ * Handles both response shapes the transport allows (a JSON body or a
6
+ * `text/event-stream` with the reply in a `data:` line) and carries the
7
+ * `Mcp-Session-Id` the server hands out. Never puts the URL (or anything of
8
+ * its path) into a result or error.
9
+ *
10
+ * @module services/connector/remote-mcp-probe.service
11
+ */
12
+ import type { RemoteMcpServer } from './remote-mcp.service.js';
13
+ /** Result of a probe. */
14
+ export type RemoteMcpProbeResult = {
15
+ ok: true;
16
+ serverName?: string;
17
+ toolCount: number;
18
+ tools: string[];
19
+ } | {
20
+ ok: false;
21
+ error: string;
22
+ };
23
+ /** Minimal fetch signature (injectable for tests). */
24
+ export type FetchLike = (url: string, init: {
25
+ method: string;
26
+ headers: Record<string, string>;
27
+ body?: string;
28
+ signal?: AbortSignal;
29
+ }) => Promise<{
30
+ status: number;
31
+ ok: boolean;
32
+ headers: {
33
+ get(name: string): string | null;
34
+ };
35
+ text(): Promise<string>;
36
+ }>;
37
+ /** A JSON-RPC response. */
38
+ interface JsonRpcResponse {
39
+ jsonrpc?: string;
40
+ id?: number | string | null;
41
+ result?: Record<string, unknown>;
42
+ error?: {
43
+ code?: number;
44
+ message?: string;
45
+ };
46
+ }
47
+ /**
48
+ * Remove every trace of the URL from a message: the whole URL, its path,
49
+ * and any long path segment (Zoho's key is one).
50
+ *
51
+ * @param message - Raw message
52
+ * @param url - Server URL
53
+ * @returns Safe message
54
+ */
55
+ export declare function scrubUrl(message: string, url: string): string;
56
+ /**
57
+ * Read a JSON-RPC reply out of a JSON or SSE body.
58
+ *
59
+ * @param contentType - Response content type
60
+ * @param body - Response text
61
+ * @param id - Request id to match
62
+ * @returns The reply, or undefined
63
+ */
64
+ export declare function parseRpcBody(contentType: string, body: string, id: number): JsonRpcResponse | undefined;
65
+ /**
66
+ * Probe a server: initialize, then list its tools (following `nextCursor`
67
+ * up to five pages).
68
+ *
69
+ * @param server - Stored server (URL and headers)
70
+ * @param fetchImpl - fetch (tests)
71
+ * @returns Tool count and names, or a safe error
72
+ */
73
+ export declare function probeRemoteMcp(server: Pick<RemoteMcpServer, 'url' | 'headers'>, fetchImpl?: FetchLike): Promise<RemoteMcpProbeResult>;
74
+ export {};
75
+ //# sourceMappingURL=remote-mcp-probe.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-mcp-probe.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/connector/remote-mcp-probe.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAI/D,yBAAyB;AACzB,MAAM,MAAM,oBAAoB,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,GACrE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjC,sDAAsD;AACtD,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,KAAK,OAAO,CAAC;IAC/I,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE;QAAE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAC9C,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CACzB,CAAC,CAAC;AAEH,2BAA2B;AAC3B,UAAU,eAAe;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAW7D;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAsBvG;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,KAAK,GAAG,SAAS,CAAC,EAAE,SAAS,GAAE,SAAyC,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAiE1K"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * "Test" for a remote MCP server: MCP `initialize`, `notifications/initialized`
3
+ * and `tools/list` over streamable HTTP, reporting the tool count and names.
4
+ *
5
+ * Handles both response shapes the transport allows (a JSON body or a
6
+ * `text/event-stream` with the reply in a `data:` line) and carries the
7
+ * `Mcp-Session-Id` the server hands out. Never puts the URL (or anything of
8
+ * its path) into a result or error.
9
+ *
10
+ * @module services/connector/remote-mcp-probe.service
11
+ */
12
+ import { REMOTE_MCP_CONSTANTS } from '../../constants.js';
13
+ const C = REMOTE_MCP_CONSTANTS;
14
+ /**
15
+ * Remove every trace of the URL from a message: the whole URL, its path,
16
+ * and any long path segment (Zoho's key is one).
17
+ *
18
+ * @param message - Raw message
19
+ * @param url - Server URL
20
+ * @returns Safe message
21
+ */
22
+ export function scrubUrl(message, url) {
23
+ let out = message.split(url).join('(server URL)');
24
+ try {
25
+ const u = new URL(url);
26
+ if (u.pathname.length > 1)
27
+ out = out.split(u.pathname).join('/…');
28
+ for (const seg of u.pathname.split('/').filter((s) => s.length >= 8))
29
+ out = out.split(seg).join('…');
30
+ if (u.search)
31
+ out = out.split(u.search).join('?…');
32
+ }
33
+ catch {
34
+ /* unparseable URL: whole-string removal above is all we can do */
35
+ }
36
+ return out;
37
+ }
38
+ /**
39
+ * Read a JSON-RPC reply out of a JSON or SSE body.
40
+ *
41
+ * @param contentType - Response content type
42
+ * @param body - Response text
43
+ * @param id - Request id to match
44
+ * @returns The reply, or undefined
45
+ */
46
+ export function parseRpcBody(contentType, body, id) {
47
+ const candidates = [];
48
+ if (contentType.includes('text/event-stream')) {
49
+ // Events are separated by blank lines; a data field may span several lines.
50
+ for (const event of body.split(/\r?\n\r?\n/)) {
51
+ const data = event.split(/\r?\n/).filter((l) => l.startsWith('data:')).map((l) => l.slice(5).trimStart()).join('\n');
52
+ if (!data)
53
+ continue;
54
+ try {
55
+ candidates.push(JSON.parse(data));
56
+ }
57
+ catch {
58
+ /* not JSON — skip */
59
+ }
60
+ }
61
+ }
62
+ else {
63
+ try {
64
+ candidates.push(JSON.parse(body));
65
+ }
66
+ catch {
67
+ return undefined;
68
+ }
69
+ }
70
+ const flat = candidates.flatMap((c) => (Array.isArray(c) ? c : [c]));
71
+ return flat.find((m) => m && m.id === id);
72
+ }
73
+ /**
74
+ * Probe a server: initialize, then list its tools (following `nextCursor`
75
+ * up to five pages).
76
+ *
77
+ * @param server - Stored server (URL and headers)
78
+ * @param fetchImpl - fetch (tests)
79
+ * @returns Tool count and names, or a safe error
80
+ */
81
+ export async function probeRemoteMcp(server, fetchImpl = fetch) {
82
+ const { url } = server;
83
+ let sessionId = null;
84
+ let protocolVersion = C.PROTOCOL_VERSION;
85
+ const post = async (payload) => {
86
+ const headers = {
87
+ ...(server.headers ?? {}),
88
+ 'Content-Type': 'application/json',
89
+ Accept: 'application/json, text/event-stream',
90
+ };
91
+ if (sessionId)
92
+ headers['Mcp-Session-Id'] = sessionId;
93
+ if (payload.method !== 'initialize')
94
+ headers['MCP-Protocol-Version'] = protocolVersion;
95
+ const res = await fetchImpl(url, { method: 'POST', headers, body: JSON.stringify(payload), signal: AbortSignal.timeout(C.TEST_TIMEOUT_MS) });
96
+ const sid = res.headers.get('mcp-session-id');
97
+ if (sid)
98
+ sessionId = sid;
99
+ return { status: res.status, contentType: res.headers.get('content-type') ?? '', body: await res.text() };
100
+ };
101
+ const call = async (id, method, params) => {
102
+ const res = await post({ jsonrpc: '2.0', id, method, params });
103
+ if (res.status === 401 || res.status === 403) {
104
+ throw new Error(`The server refused the request (${res.status}). Check the URL — it may have been regenerated.`);
105
+ }
106
+ if (res.status === 404)
107
+ throw new Error('The server was not found (404). Check the URL.');
108
+ if (res.status < 200 || res.status >= 300)
109
+ throw new Error(`The server answered ${res.status} to ${method}.`);
110
+ const reply = parseRpcBody(res.contentType, res.body, id);
111
+ if (!reply)
112
+ throw new Error(`The server's reply to ${method} was not MCP (is this an MCP server URL?).`);
113
+ if (reply.error)
114
+ throw new Error(`The server returned an error for ${method}: ${String(reply.error.message ?? reply.error.code ?? 'unknown')}`);
115
+ return reply.result ?? {};
116
+ };
117
+ try {
118
+ const init = await call(1, 'initialize', {
119
+ protocolVersion: C.PROTOCOL_VERSION,
120
+ capabilities: {},
121
+ clientInfo: { name: 'crewly', version: '1.0.0' },
122
+ });
123
+ if (typeof init.protocolVersion === 'string')
124
+ protocolVersion = init.protocolVersion;
125
+ const serverInfo = init.serverInfo;
126
+ // Notifications get 202 and no body; a failure here is not fatal.
127
+ await post({ jsonrpc: '2.0', method: 'notifications/initialized' }).catch(() => undefined);
128
+ const names = [];
129
+ let cursor;
130
+ for (let page = 0; page < 5; page++) {
131
+ const result = await call(2 + page, 'tools/list', cursor ? { cursor } : {});
132
+ const tools = Array.isArray(result.tools) ? result.tools : [];
133
+ for (const t of tools)
134
+ if (typeof t?.name === 'string')
135
+ names.push(t.name);
136
+ cursor = typeof result.nextCursor === 'string' && result.nextCursor ? result.nextCursor : undefined;
137
+ if (!cursor)
138
+ break;
139
+ }
140
+ return {
141
+ ok: true,
142
+ ...(typeof serverInfo?.name === 'string' ? { serverName: scrubUrl(serverInfo.name, url) } : {}),
143
+ toolCount: names.length,
144
+ tools: names.slice(0, C.MAX_TOOL_NAMES),
145
+ };
146
+ }
147
+ catch (err) {
148
+ const raw = err instanceof Error
149
+ ? (err.name === 'TimeoutError' || err.name === 'AbortError' ? 'The server did not answer in time.' : err.message)
150
+ : String(err);
151
+ const cause = err instanceof Error && err.cause instanceof Error ? ` (${err.cause.message})` : '';
152
+ return { ok: false, error: scrubUrl(`${raw}${cause}`, url) };
153
+ }
154
+ }
155
+ //# sourceMappingURL=remote-mcp-probe.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-mcp-probe.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/connector/remote-mcp-probe.service.ts"],"names":[],"mappings":"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"}