@@ -191,11 +191,30 @@ async function handleAdd(args: { datamate_id?: string; name?: string; scope?: "p
191191 }
192192 }
193193 try {
194- const datamate = await AltimateApi . getDatamate ( args . datamate_id )
195194 // readDatamateTransportFromIde returns the exact command from the IDE config so we
196195 // reuse the same process the extension already manages, not a second one.
197196 const transport = await readDatamateTransportFromIde ( projectRoot ( ) )
198197
198+ // altimate_change start — in workspace mode the shared `datamate` key is the
199+ // bound workspace's own engine, derived at config load. With an IDE transport
200+ // the add would go under that key; refuse and say why, before anything is
201+ // looked up — the refusal must not depend on the API being reachable.
202+ // Standalone `datamate-<name>` entries are a different key and stay the user's.
203+ const managed = transport !== null ? await managedWorkspaceLoaded ( ) : null
204+ if ( managed ) {
205+ return {
206+ title : `Datamate add: '${ DATAMATE_KEY } ' is managed by workspace "${ managed . name } "` ,
207+ metadata : { serverName : DATAMATE_KEY , managedBy : managed . id , datamateId : args . datamate_id } ,
208+ output :
209+ `This project is linked to workspace "${ managed . name } ", whose integrations are served by the ` +
210+ `workspace's own engine under the '${ DATAMATE_KEY } ' MCP server. Adding datamate '${ args . datamate_id } ' ` +
211+ `there is not applied. Unlink the project, or run without ALTIMATE_WORKSPACE, to manage that entry by hand.` ,
212+ }
213+ }
214+ // altimate_change end
215+
216+ const datamate = await AltimateApi . getDatamate ( args . datamate_id )
217+
199218 if ( transport !== null ) {
200219 log . info ( "handleAdd: IDE transport detected, entering single-gateway mode" , {
201220 serverName : DATAMATE_KEY ,
@@ -216,23 +235,6 @@ async function handleAdd(args: { datamate_id?: string; name?: string; scope?: "p
216235 ? DATAMATE_KEY
217236 : ( args . name ?? `datamate-${ slugify ( datamate . name ) } ` )
218237
219- // altimate_change start — in workspace mode the shared `datamate` key is the
220- // bound workspace's own engine, derived at config load. Adding a datamate
221- // under that key would replace it; refuse and say why. Standalone
222- // `datamate-<name>` entries are a different key and stay the user's.
223- const managed = serverName === DATAMATE_KEY ? await managedWorkspaceLoaded ( ) : null
224- if ( managed ) {
225- return {
226- title : `Datamate add: '${ DATAMATE_KEY } ' is managed by workspace "${ managed . name } "` ,
227- metadata : { serverName : DATAMATE_KEY , managedBy : managed . id , datamateId : args . datamate_id } ,
228- output :
229- `This project is linked to workspace "${ managed . name } ", whose integrations are served by the ` +
230- `workspace's own engine under the '${ DATAMATE_KEY } ' MCP server. Adding datamate '${ datamate . name } ' ` +
231- `there is not applied. Unlink the project, or run without ALTIMATE_WORKSPACE, to manage that entry by hand.` ,
232- }
233- }
234- // altimate_change end
235-
236238 const creds = transport ? undefined : await AltimateApi . getCredentials ( )
237239 const mcpConfig =
238240 transport ?. type === "remote"
@@ -356,24 +358,24 @@ async function handleCreate(args: {
356358 output : "Missing required parameter 'name'." ,
357359 }
358360 }
359- // altimate_change start — with an IDE transport the add that follows would go
360- // under the shared `datamate` key; in workspace mode that add is refused, so
361- // refuse here before creating an API datamate nothing would connect to.
362- if ( ( await readDatamateTransportFromIde ( projectRoot ( ) ) ) !== null ) {
363- const managedKey = await managedWorkspaceLoaded ( )
364- if ( managedKey ) {
365- return {
366- title : `Datamate create: '${ DATAMATE_KEY } ' is managed by workspace "${ managedKey . name } "` ,
367- metadata : { serverName : DATAMATE_KEY , managedBy : managedKey . id } ,
368- output :
369- `This project is linked to workspace "${ managedKey . name } ", whose integrations are served by the ` +
370- `workspace's own engine under the '${ DATAMATE_KEY } ' MCP server. Creating datamate '${ args . name } ' ` +
371- `here would not connect it. Unlink the project, or run without ALTIMATE_WORKSPACE, first.` ,
361+ try {
362+ // altimate_change start — with an IDE transport the add that follows would go
363+ // under the shared `datamate` key; in workspace mode that add is refused, so
364+ // refuse here before creating an API datamate nothing would connect to.
365+ if ( ( await readDatamateTransportFromIde ( projectRoot ( ) ) ) !== null ) {
366+ const managedKey = await managedWorkspaceLoaded ( )
367+ if ( managedKey ) {
368+ return {
369+ title : `Datamate create: '${ DATAMATE_KEY } ' is managed by workspace "${ managedKey . name } "` ,
370+ metadata : { serverName : DATAMATE_KEY , managedBy : managedKey . id } ,
371+ output :
372+ `This project is linked to workspace "${ managedKey . name } ", whose integrations are served by the ` +
373+ `workspace's own engine under the '${ DATAMATE_KEY } ' MCP server. Creating datamate '${ args . name } ' ` +
374+ `here would not connect it. Unlink the project, or run without ALTIMATE_WORKSPACE, first.` ,
375+ }
372376 }
373377 }
374- }
375- // altimate_change end
376- try {
378+ // altimate_change end
377379 const integrations = args . integration_ids
378380 ? await AltimateApi . resolveIntegrations ( args . integration_ids )
379381 : undefined
@@ -535,23 +537,23 @@ async function handleRemove(args: { server_name?: string; scope?: "project" | "g
535537 "Missing required parameter 'server_name'. Use 'status' to see active servers or 'list-config' to see saved configs." ,
536538 }
537539 }
538- // altimate_change start — the workspace-managed `datamate` key is not the
539- // user's to remove either: it would stop the engine under a turn and delete
540- // the entry that unlinking hands back. Standalone `datamate-<name>` entries
541- // are unaffected.
542- const managedKey = args . server_name === DATAMATE_KEY ? await managedWorkspaceLoaded ( ) : null
543- if ( managedKey ) {
544- return {
545- title : `Datamate remove: '${ DATAMATE_KEY } ' is managed by workspace "${ managedKey . name } "` ,
546- metadata : { serverName : DATAMATE_KEY , managedBy : managedKey . id } ,
547- output :
548- `This project is linked to workspace "${ managedKey . name } ", whose integrations are served by the ` +
549- `workspace's own engine under the '${ DATAMATE_KEY } ' MCP server. It is not removed. Unlink the project, ` +
550- `or run without ALTIMATE_WORKSPACE, to manage that entry by hand.` ,
551- }
552- }
553- // altimate_change end
554540 try {
541+ // altimate_change start — the workspace-managed `datamate` key is not the
542+ // user's to remove either: it would stop the engine under a turn and delete
543+ // the entry that unlinking hands back. Standalone `datamate-<name>` entries
544+ // are unaffected.
545+ const managedKey = args . server_name === DATAMATE_KEY ? await managedWorkspaceLoaded ( ) : null
546+ if ( managedKey ) {
547+ return {
548+ title : `Datamate remove: '${ DATAMATE_KEY } ' is managed by workspace "${ managedKey . name } "` ,
549+ metadata : { serverName : DATAMATE_KEY , managedBy : managedKey . id } ,
550+ output :
551+ `This project is linked to workspace "${ managedKey . name } ", whose integrations are served by the ` +
552+ `workspace's own engine under the '${ DATAMATE_KEY } ' MCP server. It is not removed. Unlink the project, ` +
553+ `or run without ALTIMATE_WORKSPACE, to manage that entry by hand.` ,
554+ }
555+ }
556+ // altimate_change end
555557 // Fully remove from runtime state (disconnect + purge from MCP list)
556558 // altimate_change start — MCP.remove (was disconnect): delete the status entry + publish
557559 // ToolsChanged so the removed server's tools stop being offered without a restart.
0 commit comments