@stigmer/mcp-server 3.11.1-dev.20260812192248 → 3.12.1

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 (115) hide show
  1. package/README.md +4 -22
  2. package/cli/mcp-server-stigmer.js +11 -11
  3. package/config.d.ts +1 -5
  4. package/config.d.ts.map +1 -1
  5. package/config.js +2 -2
  6. package/config.js.map +1 -1
  7. package/domains/agents/apply.d.ts.map +1 -1
  8. package/domains/agents/apply.js +4 -1
  9. package/domains/agents/apply.js.map +1 -1
  10. package/domains/apply-visibility.d.ts +19 -0
  11. package/domains/apply-visibility.d.ts.map +1 -0
  12. package/domains/apply-visibility.js +34 -0
  13. package/domains/apply-visibility.js.map +1 -0
  14. package/domains/environments/apply.d.ts.map +1 -1
  15. package/domains/environments/apply.js +4 -1
  16. package/domains/environments/apply.js.map +1 -1
  17. package/domains/mcpservers/apply.d.ts.map +1 -1
  18. package/domains/mcpservers/apply.js +4 -1
  19. package/domains/mcpservers/apply.js.map +1 -1
  20. package/domains/resourceuri.d.ts.map +1 -1
  21. package/domains/resourceuri.js +0 -1
  22. package/domains/resourceuri.js.map +1 -1
  23. package/domains/search/tools.d.ts.map +1 -1
  24. package/domains/search/tools.js +4 -5
  25. package/domains/search/tools.js.map +1 -1
  26. package/domains/workflows/apply.d.ts.map +1 -1
  27. package/domains/workflows/apply.js +4 -1
  28. package/domains/workflows/apply.js.map +1 -1
  29. package/gen/agent.d.ts +0 -56
  30. package/gen/agent.d.ts.map +1 -1
  31. package/gen/agent.js +2 -25
  32. package/gen/agent.js.map +1 -1
  33. package/gen/environment.js +1 -1
  34. package/gen/environment.js.map +1 -1
  35. package/gen/mcpserver.js +1 -1
  36. package/gen/mcpserver.js.map +1 -1
  37. package/gen/workflow.d.ts +2 -2
  38. package/gen/workflow.js +1 -1
  39. package/gen/workflow.js.map +1 -1
  40. package/index.d.ts +1 -1
  41. package/index.d.ts.map +1 -1
  42. package/index.js +1 -1
  43. package/index.js.map +1 -1
  44. package/package.json +3 -3
  45. package/server.d.ts +6 -18
  46. package/server.d.ts.map +1 -1
  47. package/server.js +6 -36
  48. package/server.js.map +1 -1
  49. package/src/config.ts +3 -7
  50. package/src/domains/agents/apply.ts +10 -1
  51. package/src/domains/apply-visibility.ts +47 -0
  52. package/src/domains/apply.integration.test.ts +58 -41
  53. package/src/domains/deletes.integration.test.ts +1 -25
  54. package/src/domains/environments/apply.ts +10 -1
  55. package/src/domains/mcpservers/apply.ts +10 -1
  56. package/src/domains/reads.integration.test.ts +1 -18
  57. package/src/domains/resources.integration.test.ts +0 -18
  58. package/src/domains/resourceuri.test.ts +0 -2
  59. package/src/domains/resourceuri.ts +0 -1
  60. package/src/domains/search/search.integration.test.ts +3 -5
  61. package/src/domains/search/tools.ts +4 -5
  62. package/src/domains/workflows/apply.ts +10 -1
  63. package/src/gen/agent.ts +2 -29
  64. package/src/gen/environment.ts +1 -1
  65. package/src/gen/mcpserver.ts +1 -1
  66. package/src/gen/workflow.ts +1 -1
  67. package/src/http.integration.test.ts +2 -3
  68. package/src/index.ts +0 -2
  69. package/src/server.ts +6 -36
  70. package/domains/datastores/apply.d.ts +0 -4
  71. package/domains/datastores/apply.d.ts.map +0 -1
  72. package/domains/datastores/apply.js +0 -28
  73. package/domains/datastores/apply.js.map +0 -1
  74. package/domains/datastores/delete.d.ts +0 -3
  75. package/domains/datastores/delete.d.ts.map +0 -1
  76. package/domains/datastores/delete.js +0 -38
  77. package/domains/datastores/delete.js.map +0 -1
  78. package/domains/datastores/fetch.d.ts +0 -3
  79. package/domains/datastores/fetch.d.ts.map +0 -1
  80. package/domains/datastores/fetch.js +0 -23
  81. package/domains/datastores/fetch.js.map +0 -1
  82. package/domains/datastores/resources.d.ts +0 -5
  83. package/domains/datastores/resources.d.ts.map +0 -1
  84. package/domains/datastores/resources.js +0 -16
  85. package/domains/datastores/resources.js.map +0 -1
  86. package/domains/datastores/tools.d.ts +0 -5
  87. package/domains/datastores/tools.d.ts.map +0 -1
  88. package/domains/datastores/tools.js +0 -46
  89. package/domains/datastores/tools.js.map +0 -1
  90. package/domains/records/calls.d.ts +0 -48
  91. package/domains/records/calls.d.ts.map +0 -1
  92. package/domains/records/calls.js +0 -118
  93. package/domains/records/calls.js.map +0 -1
  94. package/domains/records/errors.d.ts +0 -24
  95. package/domains/records/errors.d.ts.map +0 -1
  96. package/domains/records/errors.js +0 -79
  97. package/domains/records/errors.js.map +0 -1
  98. package/domains/records/tools.d.ts +0 -7
  99. package/domains/records/tools.d.ts.map +0 -1
  100. package/domains/records/tools.js +0 -139
  101. package/domains/records/tools.js.map +0 -1
  102. package/gen/datastore.d.ts +0 -861
  103. package/gen/datastore.d.ts.map +0 -1
  104. package/gen/datastore.js +0 -267
  105. package/gen/datastore.js.map +0 -1
  106. package/src/domains/datastores/apply.ts +0 -33
  107. package/src/domains/datastores/delete.ts +0 -47
  108. package/src/domains/datastores/fetch.ts +0 -32
  109. package/src/domains/datastores/resources.ts +0 -21
  110. package/src/domains/datastores/tools.ts +0 -76
  111. package/src/domains/records/calls.ts +0 -209
  112. package/src/domains/records/errors.ts +0 -98
  113. package/src/domains/records/records.integration.test.ts +0 -313
  114. package/src/domains/records/tools.ts +0 -210
  115. package/src/gen/datastore.ts +0 -264
@@ -6,7 +6,10 @@
6
6
  import { AgentSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
7
7
  import { AgentCommandController } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/command_pb";
8
8
 
9
+ import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
10
+
9
11
  import { agentInputToProto, type AgentInput } from "../../gen/agent.js";
12
+ import { applyDeclaredVisibility } from "../apply-visibility.js";
10
13
  import { withClient } from "../client.js";
11
14
  import { toProtoJson } from "../marshal.js";
12
15
  import { rpcError } from "../rpcerr.js";
@@ -21,7 +24,13 @@ export async function applyAgent(
21
24
  const desc = `agent "${agent.metadata?.slug ?? ""}" in org "${agent.metadata?.org ?? ""}"`;
22
25
  return withClient(AgentCommandController, serverAddress, token, async (client, callOptions) => {
23
26
  try {
24
- const result = await client.apply(agent, callOptions);
27
+ const applied = await client.apply(agent, callOptions);
28
+ const result = await applyDeclaredVisibility(
29
+ client,
30
+ callOptions,
31
+ applied,
32
+ agent.metadata?.visibility ?? ApiResourceVisibility.api_resource_visibility_unspecified,
33
+ );
25
34
  return toProtoJson(AgentSchema, result);
26
35
  } catch (err) {
27
36
  throw rpcError(err, desc);
@@ -0,0 +1,47 @@
1
+ // Declared-visibility follow-up for the apply tools (oss#573).
2
+ //
3
+ // Plain updates preserve the stored visibility on both editions — the
4
+ // updateVisibility RPC is the only door for visibility changes, where the
5
+ // server-side guards live (per-kind level support, default-instance
6
+ // rejection). So when an apply tool's input declares a visibility and the
7
+ // applied resource comes back with a different level (i.e. the resource
8
+ // already existed), we follow up with one UpdateVisibility RPC on the same
9
+ // controller. The CLI's skill-push and manifest-apply flows do the same.
10
+ //
11
+ // No-ops are skipped (input omitted visibility, create honored it, or the
12
+ // stored level already matches), so an unchanged apply costs nothing extra.
13
+ // Guard rejections propagate to the caller's rpcError wrapper — the model
14
+ // sees the real FAILED_PRECONDITION / INVALID_ARGUMENT, not a silent lie.
15
+
16
+ import { create } from "@bufbuild/protobuf";
17
+ import type { CallOptions } from "@connectrpc/connect";
18
+ import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
19
+ import { UpdateVisibilityInputSchema, type UpdateVisibilityInput } from "@stigmer/protos/ai/stigmer/commons/apiresource/io_pb";
20
+ import type { ApiResourceMetadata } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
21
+
22
+ interface HasResourceMetadata {
23
+ metadata?: ApiResourceMetadata;
24
+ }
25
+
26
+ interface UpdateVisibilityClient<T> {
27
+ updateVisibility(input: UpdateVisibilityInput, options?: CallOptions): Promise<T>;
28
+ }
29
+
30
+ /**
31
+ * Land the input-declared visibility through the guarded door when the
32
+ * applied resource's stored level differs. Returns the resource carrying the
33
+ * final visibility (the follow-up's response, or `applied` unchanged when no
34
+ * follow-up was needed).
35
+ */
36
+ export async function applyDeclaredVisibility<T extends HasResourceMetadata>(
37
+ client: UpdateVisibilityClient<T>,
38
+ callOptions: CallOptions,
39
+ applied: T,
40
+ declared: ApiResourceVisibility,
41
+ ): Promise<T> {
42
+ if (declared === ApiResourceVisibility.api_resource_visibility_unspecified) return applied;
43
+ const resourceId = applied.metadata?.id ?? "";
44
+ if (resourceId === "") return applied;
45
+ if (applied.metadata?.visibility === declared) return applied;
46
+ return client.updateVisibility(create(UpdateVisibilityInputSchema, { resourceId, visibility: declared }), callOptions);
47
+ }
@@ -1,12 +1,13 @@
1
1
  // In-process integration test for the apply tools. Drives apply_agent,
2
- // apply_mcp_server, apply_workflow, apply_environment, and apply_datastore
3
- // through the full MCP boundary and asserts the codegen projection (src/gen/*)
2
+ // apply_mcp_server, apply_workflow, and apply_environment through the
3
+ // full MCP boundary and asserts the codegen projection (src/gen/*)
4
4
  // reconstitutes the proto correctly: metadata hoist + slug generation,
5
- // enum-string conversion (including repeated enums — datastore grant verbs),
5
+ // enum-string conversion,
6
6
  // ApiResourceReference kind injection, the stdio/http oneof, the environment
7
7
  // data map with secret flags, and the recursive workflow task_config expansion
8
8
  // (http_call leaf, fork/for_each nesting).
9
9
 
10
+ import { clone } from "@bufbuild/protobuf";
10
11
  import type { ConnectRouter } from "@connectrpc/connect";
11
12
  import { connectNodeAdapter } from "@connectrpc/connect-node";
12
13
  import {
@@ -18,11 +19,8 @@ import type { AddressInfo } from "node:net";
18
19
 
19
20
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
20
21
  import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
21
- import type { Agent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
22
+ import { type Agent, AgentSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
22
23
  import { AgentCommandController } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/command_pb";
23
- import type { Datastore } from "@stigmer/protos/ai/stigmer/agentic/datastore/v1/api_pb";
24
- import { DatastoreCommandController } from "@stigmer/protos/ai/stigmer/agentic/datastore/v1/command_pb";
25
- import { DatastoreVerb, FieldType } from "@stigmer/protos/ai/stigmer/agentic/datastore/v1/spec_pb";
26
24
  import type { Environment } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/api_pb";
27
25
  import { EnvironmentCommandController } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/command_pb";
28
26
  import type { McpServer as McpServerProto } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
@@ -32,6 +30,7 @@ import { WorkflowCommandController } from "@stigmer/protos/ai/stigmer/agentic/wo
32
30
  import { WorkflowTaskKind } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/enum_pb";
33
31
  import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
34
32
  import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
33
+ import type { UpdateVisibilityInput } from "@stigmer/protos/ai/stigmer/commons/apiresource/io_pb";
35
34
  import { afterAll, beforeAll, describe, expect, it } from "vitest";
36
35
 
37
36
  import { configureLogger } from "../logger";
@@ -45,7 +44,13 @@ let appliedAgent: Agent | undefined;
45
44
  let appliedMcpServer: McpServerProto | undefined;
46
45
  let appliedWorkflow: Workflow | undefined;
47
46
  let appliedEnvironment: Environment | undefined;
48
- let appliedDatastore: Datastore | undefined;
47
+ const visibilityUpdates: UpdateVisibilityInput[] = [];
48
+
49
+ // The single-door contract (oss#573): a plain update preserves the STORED
50
+ // visibility, so the apply response can disagree with the request. This slug
51
+ // makes the mock backend simulate that — apply echoes back a pre-existing
52
+ // resource whose stored level is org, regardless of the requested one.
53
+ const STORED_ORG_SLUG = "stored-org-agent";
49
54
  const openSessions = new Set<ServerHttp2Session>();
50
55
 
51
56
  interface ToolResult {
@@ -62,8 +67,21 @@ beforeAll(async () => {
62
67
  router.service(AgentCommandController, {
63
68
  apply: (req) => {
64
69
  appliedAgent = req;
70
+ if (req.metadata?.slug === STORED_ORG_SLUG) {
71
+ const stored = clone(AgentSchema, req);
72
+ stored.metadata!.id = "agent-stored-1";
73
+ stored.metadata!.visibility = ApiResourceVisibility.visibility_org;
74
+ return stored;
75
+ }
65
76
  return req;
66
77
  },
78
+ updateVisibility: (input) => {
79
+ visibilityUpdates.push(input);
80
+ const updated = clone(AgentSchema, appliedAgent!);
81
+ updated.metadata!.id = input.resourceId;
82
+ updated.metadata!.visibility = input.visibility;
83
+ return updated;
84
+ },
67
85
  });
68
86
  router.service(McpServerCommandController, {
69
87
  apply: (req) => {
@@ -83,12 +101,6 @@ beforeAll(async () => {
83
101
  return req;
84
102
  },
85
103
  });
86
- router.service(DatastoreCommandController, {
87
- apply: (req) => {
88
- appliedDatastore = req;
89
- return req;
90
- },
91
- });
92
104
  };
93
105
  backend = createHttp2Server(connectNodeAdapter({ routes }));
94
106
  backend.on("session", (session) => {
@@ -119,7 +131,6 @@ describe("apply tools integration", () => {
119
131
  "apply_mcp_server",
120
132
  "apply_workflow",
121
133
  "apply_environment",
122
- "apply_datastore",
123
134
  ]),
124
135
  );
125
136
  });
@@ -245,6 +256,38 @@ describe("apply tools integration", () => {
245
256
  expect(forCfg.do).toHaveLength(1);
246
257
  });
247
258
 
259
+ it("apply_agent lands a declared visibility the update preserved away via UpdateVisibility (oss#573)", async () => {
260
+ const result = await callTool("apply_agent", {
261
+ name: "Stored Org Agent",
262
+ org: "acme",
263
+ visibility: "PUBLIC",
264
+ instructions: "i",
265
+ });
266
+ expect(result.isError).toBeFalsy();
267
+
268
+ // Server "preserved" stored org; the tool must follow up once through
269
+ // the guarded door and return the landed level, not the stale one.
270
+ expect(visibilityUpdates).toHaveLength(1);
271
+ expect(visibilityUpdates[0].resourceId).toBe("agent-stored-1");
272
+ expect(visibilityUpdates[0].visibility).toBe(ApiResourceVisibility.visibility_public);
273
+ const text = result.content.find((c) => c.type === "text")?.text ?? "";
274
+ expect(JSON.parse(text).metadata.visibility).toBe("visibility_public");
275
+ });
276
+
277
+ it("apply_agent skips the follow-up when the server already matches", async () => {
278
+ visibilityUpdates.length = 0;
279
+ const result = await callTool("apply_agent", {
280
+ name: "Plain Agent",
281
+ org: "acme",
282
+ visibility: "PUBLIC",
283
+ instructions: "i",
284
+ });
285
+ expect(result.isError).toBeFalsy();
286
+ // The echo backend returns the requested level (and no id) — no diff,
287
+ // no follow-up.
288
+ expect(visibilityUpdates).toHaveLength(0);
289
+ });
290
+
248
291
  it("apply_environment rebuilds the data map with secret flags", async () => {
249
292
  const result = await callTool("apply_environment", {
250
293
  name: "GitHub Creds",
@@ -267,30 +310,4 @@ describe("apply tools integration", () => {
267
310
  });
268
311
  expect(env?.spec?.data?.REGION?.isSecret).toBe(false);
269
312
  });
270
-
271
- it("apply_datastore maps field types and repeated grant verbs to enums", async () => {
272
- const result = await callTool("apply_datastore", {
273
- name: "Bookings",
274
- org: "acme",
275
- collections: [
276
- {
277
- name: "appointments",
278
- fields: [{ name: "patient", type: "string", required: true }],
279
- grants: [{ role: "assistant", verbs: ["read", "insert"], scope: "own" }],
280
- },
281
- ],
282
- });
283
- expect(result.isError).toBeFalsy();
284
-
285
- const ds = appliedDatastore;
286
- expect(ds?.kind).toBe("Datastore");
287
- expect(ds?.metadata?.slug).toBe("bookings");
288
-
289
- const collection = ds?.spec?.collections?.[0];
290
- expect(collection?.fields?.[0]?.type).toBe(FieldType.string);
291
-
292
- // Repeated enum: verb strings map to DatastoreVerb values, not raw strings.
293
- const grant = collection?.grants?.[0];
294
- expect(grant?.verbs).toEqual([DatastoreVerb.read, DatastoreVerb.insert]);
295
- });
296
313
  });
@@ -1,8 +1,7 @@
1
1
  // In-process integration test for the delete tools. Verifies the two-step
2
2
  // resolve→delete flow forwards the resolved id into the correct per-domain
3
3
  // delete-input shape: typed {value} for agent/skill/workflow, and
4
- // ApiResourceDeleteInput {resource_id} for mcp_server, environment, and
5
- // datastore.
4
+ // ApiResourceDeleteInput {resource_id} for mcp_server and environment.
6
5
 
7
6
  import { create, toJson } from "@bufbuild/protobuf";
8
7
  import type { ConnectRouter } from "@connectrpc/connect";
@@ -19,9 +18,6 @@ import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
19
18
  import { AgentSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
20
19
  import { AgentCommandController } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/command_pb";
21
20
  import { AgentQueryController } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/query_pb";
22
- import { DatastoreSchema } from "@stigmer/protos/ai/stigmer/agentic/datastore/v1/api_pb";
23
- import { DatastoreCommandController } from "@stigmer/protos/ai/stigmer/agentic/datastore/v1/command_pb";
24
- import { DatastoreQueryController } from "@stigmer/protos/ai/stigmer/agentic/datastore/v1/query_pb";
25
21
  import { EnvironmentSchema } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/api_pb";
26
22
  import { EnvironmentCommandController } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/command_pb";
27
23
  import { EnvironmentQueryController } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/query_pb";
@@ -50,18 +46,12 @@ const resolvedEnvironment = create(EnvironmentSchema, {
50
46
  kind: "environment",
51
47
  metadata: { name: "GitHub Creds", slug: "github-creds", org: "acme", id: "env-789" },
52
48
  });
53
- const resolvedDatastore = create(DatastoreSchema, {
54
- apiVersion: "v1",
55
- kind: "datastore",
56
- metadata: { name: "Bookings", slug: "bookings", org: "acme", id: "dst-012" },
57
- });
58
49
 
59
50
  let backend: Http2Server;
60
51
  let client: Client;
61
52
  let deletedAgentId: string | undefined;
62
53
  let deletedMcpResourceId: string | undefined;
63
54
  let deletedEnvironmentResourceId: string | undefined;
64
- let deletedDatastoreResourceId: string | undefined;
65
55
  const openSessions = new Set<ServerHttp2Session>();
66
56
 
67
57
  interface ToolResult {
@@ -96,13 +86,6 @@ beforeAll(async () => {
96
86
  return resolvedEnvironment;
97
87
  },
98
88
  });
99
- router.service(DatastoreQueryController, { getByReference: () => resolvedDatastore });
100
- router.service(DatastoreCommandController, {
101
- delete: (req) => {
102
- deletedDatastoreResourceId = req.resourceId;
103
- return resolvedDatastore;
104
- },
105
- });
106
89
  };
107
90
  backend = createHttp2Server(connectNodeAdapter({ routes }));
108
91
  backend.on("session", (session) => {
@@ -134,7 +117,6 @@ describe("delete tools integration", () => {
134
117
  "delete_workflow",
135
118
  "delete_mcp_server",
136
119
  "delete_environment",
137
- "delete_datastore",
138
120
  ]),
139
121
  );
140
122
  });
@@ -162,10 +144,4 @@ describe("delete tools integration", () => {
162
144
  expect(result.isError).toBeFalsy();
163
145
  expect(deletedEnvironmentResourceId).toBe("env-789");
164
146
  });
165
-
166
- it("delete_datastore resolves the id then deletes via ApiResourceDeleteInput", async () => {
167
- const result = await callTool("delete_datastore", { org: "acme", slug: "bookings" });
168
- expect(result.isError).toBeFalsy();
169
- expect(deletedDatastoreResourceId).toBe("dst-012");
170
- });
171
147
  });
@@ -11,7 +11,10 @@
11
11
  import { EnvironmentSchema } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/api_pb";
12
12
  import { EnvironmentCommandController } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/command_pb";
13
13
 
14
+ import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
15
+
14
16
  import { environmentInputToProto, type EnvironmentInput } from "../../gen/environment.js";
17
+ import { applyDeclaredVisibility } from "../apply-visibility.js";
15
18
  import { withClient } from "../client.js";
16
19
  import { toProtoJson } from "../marshal.js";
17
20
  import { rpcError } from "../rpcerr.js";
@@ -30,7 +33,13 @@ export async function applyEnvironment(
30
33
  token,
31
34
  async (client, callOptions) => {
32
35
  try {
33
- const result = await client.apply(environment, callOptions);
36
+ const applied = await client.apply(environment, callOptions);
37
+ const result = await applyDeclaredVisibility(
38
+ client,
39
+ callOptions,
40
+ applied,
41
+ environment.metadata?.visibility ?? ApiResourceVisibility.api_resource_visibility_unspecified,
42
+ );
34
43
  return toProtoJson(EnvironmentSchema, result);
35
44
  } catch (err) {
36
45
  throw rpcError(err, desc);
@@ -7,7 +7,10 @@
7
7
  import { McpServerSchema } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
8
8
  import { McpServerCommandController } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/command_pb";
9
9
 
10
+ import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
11
+
10
12
  import { mcpServerInputToProto, type McpServerInput } from "../../gen/mcpserver.js";
13
+ import { applyDeclaredVisibility } from "../apply-visibility.js";
11
14
  import { withClient } from "../client.js";
12
15
  import { toProtoJson } from "../marshal.js";
13
16
  import { rpcError } from "../rpcerr.js";
@@ -26,7 +29,13 @@ export async function applyMcpServer(
26
29
  token,
27
30
  async (client, callOptions) => {
28
31
  try {
29
- const result = await client.apply(server, callOptions);
32
+ const applied = await client.apply(server, callOptions);
33
+ const result = await applyDeclaredVisibility(
34
+ client,
35
+ callOptions,
36
+ applied,
37
+ server.metadata?.visibility ?? ApiResourceVisibility.api_resource_visibility_unspecified,
38
+ );
30
39
  return toProtoJson(McpServerSchema, result);
31
40
  } catch (err) {
32
41
  throw rpcError(err, desc);
@@ -1,5 +1,5 @@
1
1
  // In-process integration test for the read tools (get_mcp_server, get_skill,
2
- // get_workflow, get_environment, get_datastore). Stands up a real Connect
2
+ // get_workflow, get_environment). Stands up a real Connect
3
3
  // backend serving the query controllers, drives the MCP server through an
4
4
  // in-memory client, and asserts each tool returns the backend's protojson
5
5
  // verbatim (the parity contract) and that get_skill forwards its optional
@@ -17,8 +17,6 @@ import type { AddressInfo } from "node:net";
17
17
 
18
18
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
19
19
  import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
20
- import { DatastoreSchema } from "@stigmer/protos/ai/stigmer/agentic/datastore/v1/api_pb";
21
- import { DatastoreQueryController } from "@stigmer/protos/ai/stigmer/agentic/datastore/v1/query_pb";
22
20
  import { EnvironmentSchema } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/api_pb";
23
21
  import { EnvironmentQueryController } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/query_pb";
24
22
  import { McpServerSchema } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
@@ -61,11 +59,6 @@ const knownEnvironment = create(EnvironmentSchema, {
61
59
  spec: { data: { API_KEY: { value: "***REDACTED***", isSecret: true } } },
62
60
  });
63
61
 
64
- const knownDatastore = create(DatastoreSchema, {
65
- apiVersion: "v1",
66
- kind: "datastore",
67
- metadata: { name: "Bookings", slug: "bookings", org: "acme", id: "dst-1" },
68
- });
69
62
 
70
63
  let backend: Http2Server;
71
64
  let client: Client;
@@ -92,7 +85,6 @@ beforeAll(async () => {
92
85
  });
93
86
  router.service(WorkflowQueryController, { getByReference: () => knownWorkflow });
94
87
  router.service(EnvironmentQueryController, { getByReference: () => knownEnvironment });
95
- router.service(DatastoreQueryController, { getByReference: () => knownDatastore });
96
88
  };
97
89
  backend = createHttp2Server(connectNodeAdapter({ routes }));
98
90
  // Force keep-alive sessions closed on teardown, else backend.close() blocks.
@@ -125,7 +117,6 @@ describe("read tools integration", () => {
125
117
  "get_skill",
126
118
  "get_workflow",
127
119
  "get_environment",
128
- "get_datastore",
129
120
  ]),
130
121
  );
131
122
  });
@@ -169,12 +160,4 @@ describe("read tools integration", () => {
169
160
  const data = (body.spec as { data: Record<string, { value: string }> }).data;
170
161
  expect(data.API_KEY?.value).toBe("***REDACTED***");
171
162
  });
172
-
173
- it("get_datastore returns the backend protojson", async () => {
174
- const result = await callTool("get_datastore", { org: "acme", slug: "bookings" });
175
- expect(result.isError).toBeFalsy();
176
- expect(JSON.parse(result.content[0]?.text ?? "{}")).toEqual(
177
- toJson(DatastoreSchema, knownDatastore, { useProtoFieldName: true }),
178
- );
179
- });
180
163
  });
@@ -17,8 +17,6 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
17
17
  import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
18
18
  import { AgentSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
19
19
  import { AgentQueryController } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/query_pb";
20
- import { DatastoreSchema } from "@stigmer/protos/ai/stigmer/agentic/datastore/v1/api_pb";
21
- import { DatastoreQueryController } from "@stigmer/protos/ai/stigmer/agentic/datastore/v1/query_pb";
22
20
  import { EnvironmentSchema } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/api_pb";
23
21
  import { EnvironmentQueryController } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/query_pb";
24
22
  import { McpServerSchema } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
@@ -51,11 +49,6 @@ const environment = create(EnvironmentSchema, {
51
49
  kind: "environment",
52
50
  metadata: { slug: "e", org: "acme" },
53
51
  });
54
- const datastore = create(DatastoreSchema, {
55
- apiVersion: "v1",
56
- kind: "datastore",
57
- metadata: { slug: "d", org: "acme" },
58
- });
59
52
 
60
53
  let backend: Http2Server;
61
54
  let client: Client;
@@ -78,7 +71,6 @@ beforeAll(async () => {
78
71
  });
79
72
  router.service(WorkflowQueryController, { getByReference: () => workflow });
80
73
  router.service(EnvironmentQueryController, { getByReference: () => environment });
81
- router.service(DatastoreQueryController, { getByReference: () => datastore });
82
74
  };
83
75
  backend = createHttp2Server(connectNodeAdapter({ routes }));
84
76
  backend.on("session", (session) => {
@@ -111,7 +103,6 @@ describe("resource templates integration", () => {
111
103
  "stigmer_skill_version",
112
104
  "stigmer_workflow",
113
105
  "stigmer_environment",
114
- "stigmer_datastore",
115
106
  ]),
116
107
  );
117
108
  });
@@ -163,13 +154,4 @@ describe("resource templates integration", () => {
163
154
  toJson(EnvironmentSchema, environment, { useProtoFieldName: true }),
164
155
  );
165
156
  });
166
-
167
- it("reads a datastore resource", async () => {
168
- const result = (await client.readResource({
169
- uri: "stigmer://datastores/acme/d",
170
- })) as ResourceResult;
171
- expect(JSON.parse(result.contents[0]?.text ?? "{}")).toEqual(
172
- toJson(DatastoreSchema, datastore, { useProtoFieldName: true }),
173
- );
174
- });
175
157
  });
@@ -76,7 +76,6 @@ describe("buildResourceURI", () => {
76
76
  expect(buildResourceURI("skill", "acme", "s")).toBe("stigmer://skills/acme/s");
77
77
  expect(buildResourceURI("workflow", "acme", "w")).toBe("stigmer://workflows/acme/w");
78
78
  expect(buildResourceURI("environment", "acme", "e")).toBe("stigmer://environments/acme/e");
79
- expect(buildResourceURI("datastore", "acme", "d")).toBe("stigmer://datastores/acme/d");
80
79
  });
81
80
 
82
81
  it("round-trips with parseResourceURI", () => {
@@ -96,7 +95,6 @@ describe("buildResourceURI", () => {
96
95
  it("covers exactly the templated kinds", () => {
97
96
  expect(Object.keys(kindToAuthority).sort()).toEqual([
98
97
  "agent",
99
- "datastore",
100
98
  "environment",
101
99
  "mcp_server",
102
100
  "skill",
@@ -81,7 +81,6 @@ export function parseVersionedResourceURI(uri: string): VersionedResourceRef {
81
81
  */
82
82
  export const kindToAuthority: Readonly<Record<string, string>> = {
83
83
  agent: "agents",
84
- datastore: "datastores",
85
84
  environment: "environments",
86
85
  mcp_server: "mcp-servers",
87
86
  skill: "skills",
@@ -40,7 +40,6 @@ const allKindsResponse = create(SearchResponseSchema, {
40
40
  org: "acme",
41
41
  slug: "github-creds",
42
42
  }),
43
- create(SearchResultSchema, { kind: ApiResourceKind.datastore, org: "acme", slug: "bookings" }),
44
43
  ],
45
44
  });
46
45
  const emptyResponse = create(SearchResponseSchema, { entries: [] });
@@ -103,7 +102,6 @@ describe("search tool integration", () => {
103
102
  "stigmer://mcp-servers/acme/github",
104
103
  "stigmer://workflows/acme/release",
105
104
  "stigmer://environments/acme/github-creds",
106
- "stigmer://datastores/acme/bookings",
107
105
  ]);
108
106
  });
109
107
 
@@ -121,13 +119,13 @@ describe("search tool integration", () => {
121
119
  expect(result.isError).toBe(true);
122
120
  expect(result.content[0]?.text).toContain('unknown resource kind "bogus"');
123
121
  expect(result.content[0]?.text).toContain(
124
- "valid kinds: agent, skill, mcp_server, workflow, environment, datastore",
122
+ "valid kinds: agent, skill, mcp_server, workflow, environment",
125
123
  );
126
124
  });
127
125
 
128
- it("accepts the environment and datastore kinds", async () => {
126
+ it("accepts the environment kind", async () => {
129
127
  nextResponse = emptyResponse;
130
- const result = await callSearch({ kinds: ["environment", "datastore"] });
128
+ const result = await callSearch({ kinds: ["environment"] });
131
129
  expect(result.isError).toBeFalsy();
132
130
  });
133
131
 
@@ -31,7 +31,6 @@ import { textOrError } from "../toolresult.js";
31
31
  */
32
32
  const knownKinds: Readonly<Record<string, ApiResourceKind>> = {
33
33
  agent: ApiResourceKind.agent,
34
- datastore: ApiResourceKind.datastore,
35
34
  environment: ApiResourceKind.environment,
36
35
  skill: ApiResourceKind.skill,
37
36
  mcp_server: ApiResourceKind.mcp_server,
@@ -53,15 +52,15 @@ export function registerSearchTools(server: McpServer, target: BackendTarget): s
53
52
  "search",
54
53
  {
55
54
  description:
56
- "Search and list Stigmer resources (agents, skills, MCP servers, workflows, environments, " +
57
- "datastores). Set 'kinds' to filter by resource type. Set 'query' for full-text search. " +
55
+ "Search and list Stigmer resources (agents, skills, MCP servers, workflows, " +
56
+ "environments). Set 'kinds' to filter by resource type. Set 'query' for full-text search. " +
58
57
  "Set 'org' to scope to an organization. Omit 'query' to list all accessible resources.",
59
58
  inputSchema: {
60
59
  kinds: z
61
60
  .array(z.string())
62
61
  .optional()
63
62
  .describe(
64
- "Resource kinds to search. Valid: agent, skill, mcp_server, workflow, environment, datastore. Empty searches all.",
63
+ "Resource kinds to search. Valid: agent, skill, mcp_server, workflow, environment. Empty searches all.",
65
64
  ),
66
65
  query: z
67
66
  .string()
@@ -130,7 +129,7 @@ function parseKinds(raw: string[] | undefined): ApiResourceKind[] {
130
129
  const kind = knownKinds[s];
131
130
  if (kind === undefined) {
132
131
  throw new Error(
133
- `unknown resource kind "${s}"; valid kinds: agent, skill, mcp_server, workflow, environment, datastore`,
132
+ `unknown resource kind "${s}"; valid kinds: agent, skill, mcp_server, workflow, environment`,
134
133
  );
135
134
  }
136
135
  return kind;
@@ -11,7 +11,10 @@
11
11
  import { WorkflowSchema } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/api_pb";
12
12
  import { WorkflowCommandController } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/command_pb";
13
13
 
14
+ import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
15
+
14
16
  import { workflowInputToProto, type WorkflowInput } from "../../gen/workflow.js";
17
+ import { applyDeclaredVisibility } from "../apply-visibility.js";
15
18
  import { withClient } from "../client.js";
16
19
  import { toProtoJson } from "../marshal.js";
17
20
  import { rpcError } from "../rpcerr.js";
@@ -30,7 +33,13 @@ export async function applyWorkflow(
30
33
  token,
31
34
  async (client, callOptions) => {
32
35
  try {
33
- const result = await client.apply(workflow, callOptions);
36
+ const applied = await client.apply(workflow, callOptions);
37
+ const result = await applyDeclaredVisibility(
38
+ client,
39
+ callOptions,
40
+ applied,
41
+ workflow.metadata?.visibility ?? ApiResourceVisibility.api_resource_visibility_unspecified,
42
+ );
34
43
  return toProtoJson(WorkflowSchema, result);
35
44
  } catch (err) {
36
45
  throw rpcError(err, desc);