Skip to content

Commit 832ebd7

Browse files
cevianclaude
andcommitted
refactor(connections): extract manager.ts as shared configured layer
Introduce connections/manager.ts that holds the configured pool, schema, and IntegrationProvider as a singleton. Both the dev-server API and MCP tools now use the same functions (assignConnection, resolveCredentials, etc.) instead of maintaining separate pools and wrappers. - Delete resolve-credentials.ts; move resolveCredentials + getAddConnectionUrl to manager.ts, move MCP-specific error hints to tool error handlers - Add real-time connection change notifications: manager notifies listeners on assign/unassign, dev-server broadcasts via WebSocket, frontend refetches - Remove credentials_page_url from list_connections output (redundant with get_connection error hints which include workflow/node deep links) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent bc87637 commit 832ebd7

File tree

14 files changed

+201
-166
lines changed

14 files changed

+201
-166
lines changed

packages/core/dev-ui/src/hooks/useConnections.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ export function useConnections() {
3838
fetchConnections();
3939
}, [fetchConnections]);
4040

41+
// Refetch when notified of external changes (e.g. MCP tool assigned a connection)
42+
useEffect(() => {
43+
const handler = () => { fetchConnections(); };
44+
window.addEventListener("connections-changed", handler);
45+
return () => window.removeEventListener("connections-changed", handler);
46+
}, [fetchConnections]);
47+
4148
const upsert = useCallback(
4249
async (mapping: Omit<ConnectionMapping, "updated_at">) => {
4350
await fetch("/dev/api/connections", {

packages/core/dev-ui/src/hooks/useDAGSocket.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ export function useDAGSocket() {
111111
new CustomEvent("spawned", { detail: message.data.pid }),
112112
);
113113
break;
114+
115+
case "connections-changed":
116+
window.dispatchEvent(new CustomEvent("connections-changed"));
117+
break;
114118
}
115119
} catch {
116120
// Ignore malformed messages

packages/core/dev-ui/src/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ export type WSMessage =
5050
// PTY messages (server → client)
5151
| { type: "pty-data"; data: string }
5252
| { type: "pty-exit"; data: { code: number } }
53-
| { type: "pty-spawned"; data: { pid: number } };
53+
| { type: "pty-spawned"; data: { pid: number } }
54+
| { type: "connections-changed" };
5455

5556
// ---- Run History types ----
5657

packages/core/src/cli/mcp/lib/resolve-credentials.ts

Lines changed: 0 additions & 130 deletions
This file was deleted.

packages/core/src/cli/mcp/sandbox-tools/bash.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { ApiFactory } from "@tigerdata/mcp-boilerplate";
22
import { execFile } from "node:child_process";
33
import { z } from "zod";
44
import type { ConnectionCredentials } from "../../../types.js";
5-
import { resolveCredentials } from "../lib/resolve-credentials.js";
5+
import { resolveCredentials } from "../../../connections/manager.js";
66
import type { ServerContext } from "../types.js";
77

88
const DEFAULT_TIMEOUT = 120_000;

packages/core/src/cli/mcp/tools/assignConnection.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { ApiFactory } from "@tigerdata/mcp-boilerplate";
22
import { z } from "zod";
33
import type { ServerContext } from "../types.js";
4-
import { assignConnection } from "../lib/resolve-credentials.js";
4+
import { assignConnection } from "../../../connections/manager.js";
55

66
const inputSchema = {
77
integration_id: z

packages/core/src/cli/mcp/tools/getConnection.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { ApiFactory } from "@tigerdata/mcp-boilerplate";
22
import { z } from "zod";
33
import type { ServerContext } from "../types.js";
4-
import { resolveCredentials } from "../lib/resolve-credentials.js";
4+
import { resolveCredentials, getAddConnectionUrl } from "../../../connections/manager.js";
55

66
const inputSchema = {
77
integration_id: z
@@ -74,8 +74,12 @@ export const getConnectionFactory: ApiFactory<
7474
access_token: credentials.token,
7575
};
7676
} catch (err) {
77+
const msg = err instanceof Error ? err.message : String(err);
78+
const credentialsUrl = getAddConnectionUrl(integration_id, workflow_name, node_name);
79+
const urlHint = credentialsUrl ? ` Add a connection at: ${credentialsUrl}` : "";
7780
return {
78-
error: err instanceof Error ? err.message : String(err),
81+
error: `${msg} Use list_connections to check for existing connections, ` +
82+
`then assign_connection to assign one.${urlHint}`,
7983
};
8084
}
8185
},

packages/core/src/cli/mcp/tools/listConnections.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { ApiFactory } from "@tigerdata/mcp-boilerplate";
22
import { z } from "zod";
33
import type { ServerContext } from "../types.js";
4-
import { createProvider, getCredentialsPageUrl } from "../lib/resolve-credentials.js";
4+
import { getProvider } from "../../../connections/manager.js";
55

66
const inputSchema = {
77
integration_id: z
@@ -18,16 +18,11 @@ const outputSchema = {
1818
display_name: z.string().describe("Human-readable name for the connection"),
1919
}),
2020
).describe("Available connections for this integration"),
21-
credentials_page_url: z
22-
.string()
23-
.optional()
24-
.describe("URL to the Dev UI Credentials page where new connections can be added"),
2521
error: z.string().optional().describe("Error message if listing failed"),
2622
} as const;
2723

2824
type OutputSchema = {
2925
connections: Array<{ connection_id: string; display_name: string }>;
30-
credentials_page_url?: string;
3126
error?: string;
3227
};
3328

@@ -49,19 +44,16 @@ export const listConnectionsFactory: ApiFactory<
4944
},
5045
fn: async ({ integration_id }): Promise<OutputSchema> => {
5146
try {
52-
const provider = await createProvider();
53-
const connections = await provider.listConnections(integration_id);
47+
const connections = await getProvider().listConnections(integration_id);
5448
return {
5549
connections: connections.map((c) => ({
5650
connection_id: c.connection_id,
5751
display_name: c.display_name,
5852
})),
59-
credentials_page_url: getCredentialsPageUrl(integration_id),
6053
};
6154
} catch (err) {
6255
return {
6356
connections: [],
64-
credentials_page_url: getCredentialsPageUrl(integration_id),
6557
error: `Failed to list connections: ${err instanceof Error ? err.message : String(err)}`,
6658
};
6759
}

packages/core/src/cli/mcp/tools/listIntegrations.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { ApiFactory } from "@tigerdata/mcp-boilerplate";
22
import { z } from "zod";
33
import type { ServerContext } from "../types.js";
4-
import { createProvider } from "../lib/resolve-credentials.js";
4+
import { getProvider } from "../../../connections/manager.js";
55

66
const inputSchema = {} as const;
77

@@ -36,8 +36,7 @@ export const listIntegrationsFactory: ApiFactory<
3636
},
3737
fn: async (): Promise<OutputSchema> => {
3838
try {
39-
const provider = await createProvider();
40-
const integrations = await provider.listIntegrations();
39+
const integrations = await getProvider().listIntegrations();
4140
return { integrations };
4241
} catch (err) {
4342
return {

packages/core/src/connections/index.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,17 @@ export {
77
deleteConnectionByConnectionId,
88
} from "./resolver.js";
99
export type { ConnectionMapping } from "./resolver.js";
10+
export {
11+
configureConnectionManager,
12+
onConnectionChange,
13+
assignConnection,
14+
unassignConnection,
15+
unassignConnectionById,
16+
listConnectionMappings,
17+
getProvider,
18+
resolveCredentials,
19+
getAddConnectionUrl,
20+
} from "./manager.js";
1021
export { initNango, getNango, fetchCredentials } from "./nango-client.js";
1122
export type { IntegrationProvider } from "./integration-provider.js";
1223
export { createIntegrationProvider } from "./integration-provider.js";

0 commit comments

Comments
 (0)