Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/24404-cloud-connection-this-system.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@objectstack/cloud-connection': patch
---

Clause-②: no

fix(cloud-connection): the sign-in refusals and the unmanaged-install copy no longer call the running system "this environment"

- **What changed.** Inside the running system, user-facing copy names the system the user is in as "this system", or drops the noun. The seven `401 UNAUTHENTICATED` answers on `/api/v1/cloud-connection/*` now read "Sign in to connect a cloud account." (`bind/start`), "Sign in to install apps." (`install`) and "Sign in." (`bind/poll`, `unbind`, `installation`, `installed`, `org-packages`), where each used to say "Sign in to this environment …". On `/api/v1/marketplace/install-local`, the `409 RESOURCE_CONFLICT` that refuses a managed install over an unmanaged copy now names the holder as "the writable base 'BASE' — an unmanaged install of this package, or a base authored in this system — whose items are this system's own metadata", and the unmanaged install's success `note` reads "The package's metadata is now this system's own, in the base 'BASE' …".
- **Unchanged.** Every HTTP status, error code (`UNAUTHENTICATED`, `RESOURCE_CONFLICT`), `details` object and response shape. Server log lines are not touched.
10 changes: 10 additions & 0 deletions .changeset/24404-mcp-this-system.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@objectstack/mcp': patch
---

Clause-②: no

fix(mcp): the known-partial listing warning and the Connect-an-Agent bundle description say "this system"

- **What changed.** Inside the running system, user-facing copy names the system the caller is in as "this system". The warning an MCP client receives with a known-partial object listing (the `objectstack://objects` resource and the `list_objects` tool) now says "this system declares at least that many objects, possibly more", and the Connect-an-Agent UI bundle's description ends "for connecting MCP clients to this system".
- **Unchanged.** The `SERVICE_UNAVAILABLE` code that marks a partial listing, every payload shape, the portable `SKILL.md` (which names the deployment an outside agent connects to), and server log lines.
2 changes: 1 addition & 1 deletion content/docs/deployment/cloud-connection.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ button:
| *The request expired before it was approved. Start again.* | The code's lifetime ran out, or the cloud answered `expired_token`. |
| *The connection request was denied. Start again.* | The cloud answered `access_denied`. |
| *Device authorization failed: …* | The cloud ended the request with another error, named after the colon. |
| *Sign in to this environment to connect a cloud account.* (or *Sign in to this environment.* while waiting) | Your session on the server has ended. |
| *Sign in to connect a cloud account.* (or *Sign in.* while waiting) | Your session on the server has ended. |
| *No cloud control plane configured.* | The plugin is mounted without a control-plane URL. |
| a network error such as *fetch failed* | The server could not reach the cloud. |

Expand Down
14 changes: 7 additions & 7 deletions packages/cloud-connection/src/cloud-connection-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ export class CloudConnectionPlugin implements Plugin {
}
const session = await resolveSession(environmentId ?? '', c.req.raw);
if (session?.authGate) return refuseHeldSession(c, session.authGate);
if (!session?.userId) return c.json({ success: false, error: { code: 'UNAUTHENTICATED', message: 'Sign in to this environment to connect a cloud account.' } }, 401);
if (!session?.userId) return c.json({ success: false, error: { code: 'UNAUTHENTICATED', message: 'Sign in to connect a cloud account.' } }, 401);
// [#24148] Refused before any work, so a caller without the
// capability cannot learn whether a control plane is configured.
if (!(await holdsSetupAccess(c.req.raw, session))) return refuseWithoutSetupAccess(c);
Expand Down Expand Up @@ -656,7 +656,7 @@ export class CloudConnectionPlugin implements Plugin {
}
const session = await resolveSession(environmentId ?? '', c.req.raw);
if (session?.authGate) return refuseHeldSession(c, session.authGate);
if (!session?.userId) return c.json({ success: false, error: { code: 'UNAUTHENTICATED', message: 'Sign in to this environment.' } }, 401);
if (!session?.userId) return c.json({ success: false, error: { code: 'UNAUTHENTICATED', message: 'Sign in.' } }, 401);
// [#24148] This is the door that persists the binding.
if (!(await holdsSetupAccess(c.req.raw, session))) return refuseWithoutSetupAccess(c);
if (!cloudUrl) return c.json({ success: false, error: { code: 'CLOUD_UNCONFIGURED', message: 'No cloud control plane configured.' } }, 503);
Expand Down Expand Up @@ -758,7 +758,7 @@ export class CloudConnectionPlugin implements Plugin {
}
const session = await resolveSession(environmentId ?? '', c.req.raw);
if (session?.authGate) return refuseHeldSession(c, session.authGate);
if (!session?.userId) return c.json({ success: false, error: { code: 'UNAUTHENTICATED', message: 'Sign in to this environment.' } }, 401);
if (!session?.userId) return c.json({ success: false, error: { code: 'UNAUTHENTICATED', message: 'Sign in.' } }, 401);
// [#24148] Refused before the revoke and before the local clear.
if (!(await holdsSetupAccess(c.req.raw, session))) return refuseWithoutSetupAccess(c);

Expand Down Expand Up @@ -810,7 +810,7 @@ export class CloudConnectionPlugin implements Plugin {
const session = await resolveSession(environmentId, c.req.raw);
if (session?.authGate) return refuseHeldSession(c, session.authGate);
if (!session?.userId) {
return c.json({ success: false, error: { code: 'UNAUTHENTICATED', message: 'Sign in to this environment to install apps.' } }, 401);
return c.json({ success: false, error: { code: 'UNAUTHENTICATED', message: 'Sign in to install apps.' } }, 401);
}

if (!cloudUrl || !credential()) {
Expand Down Expand Up @@ -864,7 +864,7 @@ export class CloudConnectionPlugin implements Plugin {
const session = await resolveSession(environmentId, c.req.raw);
if (session?.authGate) return refuseHeldSession(c, session.authGate);
if (!session?.userId) {
return c.json({ success: false, error: { code: 'UNAUTHENTICATED', message: 'Sign in to this environment.' } }, 401);
return c.json({ success: false, error: { code: 'UNAUTHENTICATED', message: 'Sign in.' } }, 401);
}

let packageId = '';
Expand Down Expand Up @@ -927,7 +927,7 @@ export class CloudConnectionPlugin implements Plugin {
const session = await resolveSession(environmentId, c.req.raw);
if (session?.authGate) return refuseHeldSession(c, session.authGate);
if (!session?.userId) {
return c.json({ success: false, error: { code: 'UNAUTHENTICATED', message: 'Sign in to this environment.' } }, 401);
return c.json({ success: false, error: { code: 'UNAUTHENTICATED', message: 'Sign in.' } }, 401);
}

if (!cloudUrl || !credential()) {
Expand Down Expand Up @@ -965,7 +965,7 @@ export class CloudConnectionPlugin implements Plugin {
const session = await resolveSession(environmentId ?? '', c.req.raw);
if (session?.authGate) return refuseHeldSession(c, session.authGate);
if (!session?.userId) {
return c.json({ success: false, error: { code: 'UNAUTHENTICATED', message: 'Sign in to this environment.' } }, 401);
return c.json({ success: false, error: { code: 'UNAUTHENTICATED', message: 'Sign in.' } }, 401);
}

if (!cloudUrl || !credential()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ describe('install-local — a managed install never takes over an unmanaged copy
expect(res.status).toBe(409);
expect(res.payload.error.code).toBe('RESOURCE_CONFLICT');
expect(res.payload.error.details).toEqual({ namespace: 'crm', base: 'com.example.crm-copy' });
expect(res.payload.error.message).toContain("held by the environment base 'com.example.crm-copy'");
expect(res.payload.error.message).toContain("'com.example.crm-copy'");
expect(h.register).not.toHaveBeenCalled();
expect(h.syncSchemas).not.toHaveBeenCalled();
expect(h.ledgerHas('com.example.crm')).toBe(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1494,8 +1494,8 @@ export class MarketplaceInstallLocalPlugin implements Plugin {
error: {
code: 'RESOURCE_CONFLICT',
message: `Package '${manifestId}' cannot be installed managed: its namespace '${copyBase.namespace}' is held by `
+ `the environment base '${copyBase.base}' — an unmanaged install of this package, or a base authored `
+ 'in this environment — whose items are this environment\'s own metadata. A managed '
+ `the writable base '${copyBase.base}' — an unmanaged install of this package, or a base authored `
+ 'in this system — whose items are this system\'s own metadata. A managed '
+ 'install would hand that namespace to the package and stop serving them. Keep the copy (it follows '
+ `no upgrade), or uninstall the base '${copyBase.base}' first; its items go with it.`,
details: { namespace: copyBase.namespace, base: copyBase.base },
Expand Down Expand Up @@ -2559,7 +2559,7 @@ export class MarketplaceInstallLocalPlugin implements Plugin {
},
}
: {}),
note: `The package's metadata is now this environment's own, in the base '${result.targetPackageId}', `
note: `The package's metadata is now this system's own, in the base '${result.targetPackageId}', `
+ 'and it follows no upgrade. Refresh the console to see it.',
},
}, 200);
Expand Down
2 changes: 1 addition & 1 deletion packages/mcp/src/connect-ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export const CONNECT_AGENT_UI_BUNDLE = {
type: 'plugin',
scope: 'system',
name: 'Connect an Agent UI',
description: 'Connect-an-Agent page + Setup and Account navigation for connecting MCP clients to this environment.',
description: 'Connect-an-Agent page + Setup and Account navigation for connecting MCP clients to this system.',
pages: [CONNECT_AGENT_PAGE],
// Both entries point at the one `connect_agent` page and share the item id.
// That is legal and deliberate, read off the fold rather than assumed: the
Expand Down
2 changes: 1 addition & 1 deletion packages/mcp/src/metadata-completeness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export function metadataPartialListingSentence(plural: string, served: number):
return (
`The metadata service could not be fully read, so this listing of ${plural} is known to be INCOMPLETE. `
+ `${served} ${served === 1 ? 'is' : 'are'} being served and the total is withheld — `
+ `this environment declares at least that many ${plural}, possibly more. `
+ `this system declares at least that many ${plural}, possibly more. `
+ 'Retry once the metadata service is reachable.'
);
}
Expand Down
Loading