@essentialai/cogent-bridge
Version:
Cogent Bridge — cross-agent comms for Claude Code, OpenAI Codex and Slack. Codex users: install with `curl -fsSL https://cogent.tools/install.sh | sh`, then start with `cogent-codex` for real-time peer wake.
123 lines • 5.96 kB
JavaScript
import crypto from "node:crypto";
import { z } from "zod";
import { getConfig } from "../config.js";
import { successResult, errorResult } from "../errors.js";
import { saveCredentials, markJoinedInProcess, markCloudAttemptInProcess } from "../cloud/credential-store.js";
import { logger } from "../logger.js";
/**
* Register the cogent_create_session MCP tool.
*
* Creates a new cloud bridge session on the relay server.
* Only available when COGENT_ENDPOINT is configured.
* After creation, persists credentials locally and reinitializes
* the cloud backend so runtime HttpClient and CloudWsClient use
* the new token/sessionId.
*/
export function registerCreateSessionTool(server) {
server.registerTool("cogent_create_session", {
title: "Create Cloud Session",
description: "Create a new cloud bridge session on the relay server. " +
"Returns session ID and secret for other peers to join. " +
"Only available when COGENT_ENDPOINT is configured.",
inputSchema: {
label: z
.string()
.optional()
.describe("Human-readable label for the session"),
secret: z
.string()
.min(8)
.optional()
.describe("Shared secret for session authentication (min 8 chars). " +
"Auto-generated if omitted."),
},
annotations: {
readOnlyHint: false,
destructiveHint: false,
idempotentHint: false,
openWorldHint: true,
},
}, async ({ label, secret }) => {
try {
// Record that a cloud create was ATTEMPTED (before any network call), so a
// subsequent cogent_register_peer can tell a failed create from "no cloud
// attempt at all" and refuse to silently fall back (T0.1, shipped 3.12.5).
markCloudAttemptInProcess();
const config = getConfig();
if (!config.COGENT_ENDPOINT) {
return errorResult(new Error("COGENT_ENDPOINT not configured. Set it to use cloud mode."));
}
// Generate secret if not provided (32 hex chars, well above min 8)
const sessionSecret = secret ?? crypto.randomBytes(16).toString("hex");
// POST to create session (unauthenticated endpoint -- no token yet)
const resp = await fetch(`${config.COGENT_ENDPOINT}/api/sessions`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ secret: sessionSecret, label }),
});
if (!resp.ok) {
const body = await resp.text().catch(() => "");
return errorResult(new Error(`Failed to create session: HTTP ${resp.status}${body ? ` - ${body}` : ""}`));
}
const data = (await resp.json());
// Persist credentials locally (include label for future resolution)
await saveCredentials({
endpoint: config.COGENT_ENDPOINT,
sessionId: data.sessionId,
token: data.token,
label: data.label,
savedAt: new Date().toISOString(),
});
// Gates the persisted-credentials fallback in register-peer / startup for this process.
markJoinedInProcess();
// Reinitialize cloud backend with new credentials.
// Uses dynamic import to avoid compile-time dependency on startup.ts
// (reinitCloudBackend is added in Plan 05). Cast to Record to avoid
// TS2339 since the export doesn't exist yet.
try {
const startupModule = (await import("../startup.js"));
if (typeof startupModule.reinitCloudBackend === "function") {
await startupModule.reinitCloudBackend(config.COGENT_ENDPOINT, data.sessionId, data.token);
logger.info("Cloud backend reinitialized with new session credentials");
}
}
catch (err) {
// reinitCloudBackend may not exist yet (Plan 05 adds it).
// Credentials are persisted, so a restart will pick them up.
logger.debug(`Backend reinit not available: ${err}`);
}
return successResult({
success: true,
sessionId: data.sessionId,
label: data.label,
secret: sessionSecret,
token: data.token,
createdAt: data.createdAt,
config_snippet: {
env_vars: `COGENT_ENDPOINT=${config.COGENT_ENDPOINT}\n` +
`COGENT_SESSION_ID=${data.label ?? data.sessionId}\n` +
`COGENT_SECRET=${sessionSecret}\n` +
`COGENT_PLATFORM=${config.COGENT_PLATFORM}`,
mcp_config: {
"cogent": {
command: "npx",
args: ["-y", "@essentialai/cogent-bridge"],
env: {
COGENT_ENDPOINT: config.COGENT_ENDPOINT,
COGENT_SESSION_ID: data.label ?? data.sessionId,
COGENT_SECRET: sessionSecret,
COGENT_PLATFORM: config.COGENT_PLATFORM,
},
},
},
},
note: `Session created with label "${data.label ?? data.sessionId}". Share the secret with peers who need to join. Credentials saved locally. Cloud backend updated.`,
});
}
catch (err) {
logger.error("create-session failed", { error: err });
return errorResult(err);
}
});
}
//# sourceMappingURL=create-session.js.map