@stigmer/mcp-server 3.2.3 → 3.4.0
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.
- package/README.md +60 -13
- package/cli/mcp-server-stigmer.js +13 -9
- package/config.d.ts +12 -0
- package/config.d.ts.map +1 -1
- package/config.js +5 -0
- package/config.js.map +1 -1
- package/domains/agentexecutions/approve.d.ts +9 -0
- package/domains/agentexecutions/approve.d.ts.map +1 -0
- package/domains/agentexecutions/approve.js +46 -0
- package/domains/agentexecutions/approve.js.map +1 -0
- package/domains/agentexecutions/fetch.d.ts +28 -0
- package/domains/agentexecutions/fetch.d.ts.map +1 -0
- package/domains/agentexecutions/fetch.js +82 -0
- package/domains/agentexecutions/fetch.js.map +1 -0
- package/domains/agentexecutions/run.d.ts +27 -0
- package/domains/agentexecutions/run.d.ts.map +1 -0
- package/domains/agentexecutions/run.js +87 -0
- package/domains/agentexecutions/run.js.map +1 -0
- package/domains/agentexecutions/tools.d.ts +5 -0
- package/domains/agentexecutions/tools.d.ts.map +1 -0
- package/domains/agentexecutions/tools.js +97 -0
- package/domains/agentexecutions/tools.js.map +1 -0
- package/domains/datastores/apply.d.ts +4 -0
- package/domains/datastores/apply.d.ts.map +1 -0
- package/domains/datastores/apply.js +28 -0
- package/domains/datastores/apply.js.map +1 -0
- package/domains/datastores/delete.d.ts +3 -0
- package/domains/datastores/delete.d.ts.map +1 -0
- package/domains/datastores/delete.js +38 -0
- package/domains/datastores/delete.js.map +1 -0
- package/domains/datastores/fetch.d.ts +3 -0
- package/domains/datastores/fetch.d.ts.map +1 -0
- package/domains/datastores/fetch.js +23 -0
- package/domains/datastores/fetch.js.map +1 -0
- package/domains/datastores/resources.d.ts +5 -0
- package/domains/datastores/resources.d.ts.map +1 -0
- package/domains/datastores/resources.js +16 -0
- package/domains/datastores/resources.js.map +1 -0
- package/domains/datastores/tools.d.ts +5 -0
- package/domains/datastores/tools.d.ts.map +1 -0
- package/domains/datastores/tools.js +46 -0
- package/domains/datastores/tools.js.map +1 -0
- package/domains/environments/apply.d.ts +4 -0
- package/domains/environments/apply.d.ts.map +1 -0
- package/domains/environments/apply.js +30 -0
- package/domains/environments/apply.js.map +1 -0
- package/domains/environments/delete.d.ts +3 -0
- package/domains/environments/delete.d.ts.map +1 -0
- package/domains/environments/delete.js +36 -0
- package/domains/environments/delete.js.map +1 -0
- package/domains/environments/fetch.d.ts +6 -0
- package/domains/environments/fetch.d.ts.map +1 -0
- package/domains/environments/fetch.js +30 -0
- package/domains/environments/fetch.js.map +1 -0
- package/domains/environments/resources.d.ts +5 -0
- package/domains/environments/resources.d.ts.map +1 -0
- package/domains/environments/resources.js +16 -0
- package/domains/environments/resources.js.map +1 -0
- package/domains/environments/tools.d.ts +5 -0
- package/domains/environments/tools.d.ts.map +1 -0
- package/domains/environments/tools.js +51 -0
- package/domains/environments/tools.js.map +1 -0
- package/domains/executions/cancel.d.ts +9 -0
- package/domains/executions/cancel.d.ts.map +1 -0
- package/domains/executions/cancel.js +114 -0
- package/domains/executions/cancel.js.map +1 -0
- package/domains/executions/tools.d.ts +5 -0
- package/domains/executions/tools.d.ts.map +1 -0
- package/domains/executions/tools.js +28 -0
- package/domains/executions/tools.js.map +1 -0
- package/domains/records/calls.d.ts +48 -0
- package/domains/records/calls.d.ts.map +1 -0
- package/domains/records/calls.js +118 -0
- package/domains/records/calls.js.map +1 -0
- package/domains/records/errors.d.ts +24 -0
- package/domains/records/errors.d.ts.map +1 -0
- package/domains/records/errors.js +79 -0
- package/domains/records/errors.js.map +1 -0
- package/domains/records/tools.d.ts +7 -0
- package/domains/records/tools.d.ts.map +1 -0
- package/domains/records/tools.js +139 -0
- package/domains/records/tools.js.map +1 -0
- package/domains/resourceuri.d.ts.map +1 -1
- package/domains/resourceuri.js +2 -0
- package/domains/resourceuri.js.map +1 -1
- package/domains/search/tools.d.ts.map +1 -1
- package/domains/search/tools.js +10 -7
- package/domains/search/tools.js.map +1 -1
- package/domains/skills/tools.d.ts.map +1 -1
- package/domains/skills/tools.js +25 -1
- package/domains/skills/tools.js.map +1 -1
- package/domains/skills/versions.d.ts +9 -0
- package/domains/skills/versions.d.ts.map +1 -0
- package/domains/skills/versions.js +31 -0
- package/domains/skills/versions.js.map +1 -0
- package/domains/workflowexecutions/approvals.d.ts +17 -0
- package/domains/workflowexecutions/approvals.d.ts.map +1 -0
- package/domains/workflowexecutions/approvals.js +61 -0
- package/domains/workflowexecutions/approvals.js.map +1 -0
- package/domains/workflowexecutions/run.d.ts +12 -0
- package/domains/workflowexecutions/run.d.ts.map +1 -0
- package/domains/workflowexecutions/run.js +69 -0
- package/domains/workflowexecutions/run.js.map +1 -0
- package/domains/workflowexecutions/tools.d.ts.map +1 -1
- package/domains/workflowexecutions/tools.js +89 -6
- package/domains/workflowexecutions/tools.js.map +1 -1
- package/domains/workflows/tools.d.ts.map +1 -1
- package/domains/workflows/tools.js +69 -5
- package/domains/workflows/tools.js.map +1 -1
- package/domains/workflows/versions.d.ts +29 -0
- package/domains/workflows/versions.d.ts.map +1 -0
- package/domains/workflows/versions.js +99 -0
- package/domains/workflows/versions.js.map +1 -0
- package/gen/agent.d.ts +56 -0
- package/gen/agent.d.ts.map +1 -1
- package/gen/agent.js +24 -1
- package/gen/agent.js.map +1 -1
- package/gen/datastore.d.ts +861 -0
- package/gen/datastore.d.ts.map +1 -0
- package/gen/datastore.js +267 -0
- package/gen/datastore.js.map +1 -0
- package/gen/environment.d.ts +77 -0
- package/gen/environment.d.ts.map +1 -0
- package/gen/environment.js +62 -0
- package/gen/environment.js.map +1 -0
- package/gen/workflow.d.ts +4 -4
- package/index.d.ts +2 -2
- package/index.d.ts.map +1 -1
- package/index.js +4 -4
- package/index.js.map +1 -1
- package/package.json +3 -3
- package/server.d.ts +31 -1
- package/server.d.ts.map +1 -1
- package/server.js +53 -3
- package/server.js.map +1 -1
- package/src/config.ts +19 -0
- package/src/domains/agentexecutions/approve.ts +67 -0
- package/src/domains/agentexecutions/fetch.ts +112 -0
- package/src/domains/agentexecutions/run.ts +112 -0
- package/src/domains/agentexecutions/tools.ts +139 -0
- package/src/domains/apply.integration.test.ts +82 -6
- package/src/domains/datastores/apply.ts +33 -0
- package/src/domains/datastores/delete.ts +47 -0
- package/src/domains/datastores/fetch.ts +32 -0
- package/src/domains/datastores/resources.ts +21 -0
- package/src/domains/datastores/tools.ts +76 -0
- package/src/domains/deletes.integration.test.ts +49 -2
- package/src/domains/environments/apply.ts +40 -0
- package/src/domains/environments/delete.ts +45 -0
- package/src/domains/environments/fetch.ts +39 -0
- package/src/domains/environments/resources.ts +21 -0
- package/src/domains/environments/tools.ts +81 -0
- package/src/domains/executions/cancel.ts +148 -0
- package/src/domains/executions/tools.ts +45 -0
- package/src/domains/executions.integration.test.ts +376 -0
- package/src/domains/reads.integration.test.ts +51 -5
- package/src/domains/records/calls.ts +209 -0
- package/src/domains/records/errors.ts +98 -0
- package/src/domains/records/records.integration.test.ts +313 -0
- package/src/domains/records/tools.ts +210 -0
- package/src/domains/resources.integration.test.ts +38 -2
- package/src/domains/resourceuri.test.ts +11 -2
- package/src/domains/resourceuri.ts +2 -0
- package/src/domains/search/search.integration.test.ts +18 -2
- package/src/domains/search/tools.ts +12 -7
- package/src/domains/skills/tools.ts +34 -1
- package/src/domains/skills/versions.ts +47 -0
- package/src/domains/versions.integration.test.ts +212 -0
- package/src/domains/workflowexecutions/approvals.ts +102 -0
- package/src/domains/workflowexecutions/run.ts +87 -0
- package/src/domains/workflowexecutions/tools.ts +120 -6
- package/src/domains/workflows/tools.ts +90 -7
- package/src/domains/workflows/versions.ts +147 -0
- package/src/gen/agent.ts +28 -1
- package/src/gen/datastore.ts +264 -0
- package/src/gen/environment.ts +66 -0
- package/src/http.integration.test.ts +1 -0
- package/src/index.ts +12 -5
- package/src/server.ts +71 -5
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Workflow-execution start path for the run_workflow tool.
|
|
2
|
+
//
|
|
3
|
+
// Mirrors the CLI's workflow run branch (client-apps/cli/src/commands/run.ts +
|
|
4
|
+
// resources/run/create.ts): resolve the org/slug reference to the workflow ID,
|
|
5
|
+
// then create the execution. Asynchronous like run_agent — the tool returns
|
|
6
|
+
// the created execution (wex_* ID) and observation happens through the
|
|
7
|
+
// existing get_workflow_execution / get_workflow_execution_events tools.
|
|
8
|
+
|
|
9
|
+
import { createClient } from "@connectrpc/connect";
|
|
10
|
+
import { create as createMessage } from "@bufbuild/protobuf";
|
|
11
|
+
import { WorkflowQueryController } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/query_pb";
|
|
12
|
+
import { WorkflowExecutionSchema } from "@stigmer/protos/ai/stigmer/agentic/workflowexecution/v1/api_pb";
|
|
13
|
+
import { WorkflowExecutionCommandController } from "@stigmer/protos/ai/stigmer/agentic/workflowexecution/v1/command_pb";
|
|
14
|
+
import { WorkflowExecutionSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/workflowexecution/v1/spec_pb";
|
|
15
|
+
import { ExecutionValueSchema } from "@stigmer/protos/ai/stigmer/agentic/executioncontext/v1/spec_pb";
|
|
16
|
+
import { ApiResourceMetadataSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
|
|
17
|
+
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
18
|
+
|
|
19
|
+
import { executionName, toExecutionValues } from "../agentexecutions/run.js";
|
|
20
|
+
import { withTransport } from "../client.js";
|
|
21
|
+
import { toProtoJson } from "../marshal.js";
|
|
22
|
+
import { rpcError } from "../rpcerr.js";
|
|
23
|
+
|
|
24
|
+
/** apiVersion stamped on created executions; mirrors the CLI's run stack. */
|
|
25
|
+
const API_VERSION = "agentic.stigmer.ai/v1";
|
|
26
|
+
|
|
27
|
+
export interface RunWorkflowArgs {
|
|
28
|
+
readonly org: string;
|
|
29
|
+
readonly workflow: string;
|
|
30
|
+
readonly message?: string;
|
|
31
|
+
readonly runtimeEnv?: Record<string, string>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Start a workflow execution: resolve org/slug → workflow ID, then create the
|
|
36
|
+
* execution. Returns the created execution as protojson.
|
|
37
|
+
*/
|
|
38
|
+
export async function runWorkflow(
|
|
39
|
+
serverAddress: string,
|
|
40
|
+
token: string,
|
|
41
|
+
args: RunWorkflowArgs,
|
|
42
|
+
): Promise<string> {
|
|
43
|
+
const desc = `workflow "${args.workflow}" in org "${args.org}"`;
|
|
44
|
+
return withTransport(serverAddress, token, async (transport, callOptions) => {
|
|
45
|
+
const query = createClient(WorkflowQueryController, transport);
|
|
46
|
+
let workflowId: string;
|
|
47
|
+
try {
|
|
48
|
+
const workflow = await query.getByReference(
|
|
49
|
+
{ org: args.org, kind: ApiResourceKind.workflow, slug: args.workflow },
|
|
50
|
+
callOptions,
|
|
51
|
+
);
|
|
52
|
+
workflowId = workflow.metadata?.id ?? "";
|
|
53
|
+
} catch (err) {
|
|
54
|
+
throw rpcError(err, desc);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Workflow tasks resolve their org through the runtime env; the CLI
|
|
58
|
+
// injects STIGMER_ORG_ID the same way, so a caller-supplied value wins.
|
|
59
|
+
const runtimeEnv = toExecutionValues(args.runtimeEnv);
|
|
60
|
+
if (runtimeEnv.STIGMER_ORG_ID === undefined) {
|
|
61
|
+
runtimeEnv.STIGMER_ORG_ID = createMessage(ExecutionValueSchema, {
|
|
62
|
+
value: args.org,
|
|
63
|
+
isSecret: false,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const execution = createMessage(WorkflowExecutionSchema, {
|
|
68
|
+
apiVersion: API_VERSION,
|
|
69
|
+
kind: "WorkflowExecution",
|
|
70
|
+
metadata: createMessage(ApiResourceMetadataSchema, { name: executionName(), org: args.org }),
|
|
71
|
+
spec: createMessage(WorkflowExecutionSpecSchema, {
|
|
72
|
+
workflowId,
|
|
73
|
+
// Empty message means "just run" — the CLI applies the same default.
|
|
74
|
+
triggerMessage: (args.message ?? "") === "" ? "execute" : args.message,
|
|
75
|
+
runtimeEnv,
|
|
76
|
+
}),
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const command = createClient(WorkflowExecutionCommandController, transport);
|
|
80
|
+
try {
|
|
81
|
+
const created = await command.create(execution, callOptions);
|
|
82
|
+
return toProtoJson(WorkflowExecutionSchema, created);
|
|
83
|
+
} catch (err) {
|
|
84
|
+
throw rpcError(err, `execution of ${desc}`);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
// MCP tools for
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
1
|
+
// MCP tools for the WorkflowExecution domain: start a run (run_workflow),
|
|
2
|
+
// observe it (get_workflow_execution, get_workflow_execution_events — backed
|
|
3
|
+
// by WorkflowExecutionQueryController.get/getEventLog), and answer its
|
|
4
|
+
// human_input tasks (list_pending_approvals, submit_workflow_task_approval).
|
|
5
|
+
// The observation tools predate the rest and their names/descriptions are
|
|
6
|
+
// part of the original Go-parity contract
|
|
7
|
+
// (mcp-server/internal/domains/workflowexecutions/tools.go).
|
|
6
8
|
|
|
7
9
|
import type { MessageInitShape } from "@bufbuild/protobuf";
|
|
8
10
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -18,9 +20,47 @@ import { resolveToken, withClient, type BackendTarget } from "../client.js";
|
|
|
18
20
|
import { toProtoJson } from "../marshal.js";
|
|
19
21
|
import { rpcError } from "../rpcerr.js";
|
|
20
22
|
import { textOrError } from "../toolresult.js";
|
|
23
|
+
import { listPendingApprovals, submitWorkflowTaskApproval } from "./approvals.js";
|
|
24
|
+
import { runWorkflow } from "./run.js";
|
|
21
25
|
|
|
22
26
|
/** Register the workflow-execution tools; returns the registered tool names. */
|
|
23
27
|
export function registerWorkflowExecutionTools(server: McpServer, target: BackendTarget): string[] {
|
|
28
|
+
server.registerTool(
|
|
29
|
+
"run_workflow",
|
|
30
|
+
{
|
|
31
|
+
description:
|
|
32
|
+
"Start a workflow execution (asynchronous). Returns immediately with the created execution " +
|
|
33
|
+
"(wex_* ID) while the run continues in the background — poll get_workflow_execution and " +
|
|
34
|
+
"get_workflow_execution_events to observe progress and diagnose failures.",
|
|
35
|
+
inputSchema: {
|
|
36
|
+
org: z.string().describe("Organization slug that owns the workflow (e.g. stigmer)."),
|
|
37
|
+
workflow: z
|
|
38
|
+
.string()
|
|
39
|
+
.describe("Workflow slug — the unique identifier within the org (e.g. release-notes)."),
|
|
40
|
+
message: z
|
|
41
|
+
.string()
|
|
42
|
+
.optional()
|
|
43
|
+
.describe("Trigger message passed to the workflow. Omit to run with the default trigger."),
|
|
44
|
+
runtime_env: z
|
|
45
|
+
.record(z.string())
|
|
46
|
+
.optional()
|
|
47
|
+
.describe(
|
|
48
|
+
"Non-secret runtime environment values (name → value) injected into the run. " +
|
|
49
|
+
"Secrets must come from Environments referenced by the workflow, never through this tool.",
|
|
50
|
+
),
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
(args, extra) =>
|
|
54
|
+
textOrError(() =>
|
|
55
|
+
runWorkflow(target.serverAddress, resolveToken(extra, target.apiKey), {
|
|
56
|
+
org: args.org,
|
|
57
|
+
workflow: args.workflow,
|
|
58
|
+
message: args.message,
|
|
59
|
+
runtimeEnv: args.runtime_env,
|
|
60
|
+
}),
|
|
61
|
+
),
|
|
62
|
+
);
|
|
63
|
+
|
|
24
64
|
server.registerTool(
|
|
25
65
|
"get_workflow_execution",
|
|
26
66
|
{
|
|
@@ -67,7 +107,81 @@ export function registerWorkflowExecutionTools(server: McpServer, target: Backen
|
|
|
67
107
|
),
|
|
68
108
|
);
|
|
69
109
|
|
|
70
|
-
|
|
110
|
+
server.registerTool(
|
|
111
|
+
"list_pending_approvals",
|
|
112
|
+
{
|
|
113
|
+
description:
|
|
114
|
+
"List workflow tasks waiting for a human decision across an organization — an approvals " +
|
|
115
|
+
"inbox. Each entry carries the execution ID, task name, requester, timeout, and the form " +
|
|
116
|
+
"schema when the task defines one; respond with submit_workflow_task_approval. " +
|
|
117
|
+
"(Agent-execution approvals are not listed here — they surface in get_agent_execution's " +
|
|
118
|
+
"status.pending_approvals.)",
|
|
119
|
+
inputSchema: {
|
|
120
|
+
org: z.string().describe("Organization slug to scope the query (e.g. stigmer)."),
|
|
121
|
+
page_size: z
|
|
122
|
+
.number()
|
|
123
|
+
.int()
|
|
124
|
+
.optional()
|
|
125
|
+
.describe("Maximum entries per page (default 20, max 100)."),
|
|
126
|
+
page_token: z
|
|
127
|
+
.string()
|
|
128
|
+
.optional()
|
|
129
|
+
.describe("Pagination token from a previous response's next_page_token."),
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
(args, extra) =>
|
|
133
|
+
textOrError(() =>
|
|
134
|
+
listPendingApprovals(target.serverAddress, resolveToken(extra, target.apiKey), {
|
|
135
|
+
org: args.org,
|
|
136
|
+
pageSize: args.page_size,
|
|
137
|
+
pageToken: args.page_token,
|
|
138
|
+
}),
|
|
139
|
+
),
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
server.registerTool(
|
|
143
|
+
"submit_workflow_task_approval",
|
|
144
|
+
{
|
|
145
|
+
description:
|
|
146
|
+
"Submit a reviewer decision for a workflow human_input task that is waiting for a signal. " +
|
|
147
|
+
"outcome must match one of the task's configured outcome names (default: approve or deny). " +
|
|
148
|
+
"When the task defines a form_schema (see list_pending_approvals), provide matching " +
|
|
149
|
+
"form_data. Returns the updated workflow execution.",
|
|
150
|
+
inputSchema: {
|
|
151
|
+
execution_id: z.string().describe("Workflow execution ID (wex_* format)."),
|
|
152
|
+
task_name: z.string().describe("Name of the waiting human_input task."),
|
|
153
|
+
outcome: z
|
|
154
|
+
.string()
|
|
155
|
+
.describe(
|
|
156
|
+
"Decision outcome. Must match a configured outcome name of the task " +
|
|
157
|
+
"(e.g. approve, deny, needs_revision); approve/deny when none are configured.",
|
|
158
|
+
),
|
|
159
|
+
comment: z.string().optional().describe("Reviewer comment, stored in the audit trail."),
|
|
160
|
+
form_data: z
|
|
161
|
+
.record(z.unknown())
|
|
162
|
+
.optional()
|
|
163
|
+
.describe("Response form data conforming to the task's form_schema, when it defines one."),
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
(args, extra) =>
|
|
167
|
+
textOrError(() =>
|
|
168
|
+
submitWorkflowTaskApproval(target.serverAddress, resolveToken(extra, target.apiKey), {
|
|
169
|
+
executionId: args.execution_id,
|
|
170
|
+
taskName: args.task_name,
|
|
171
|
+
outcome: args.outcome,
|
|
172
|
+
comment: args.comment,
|
|
173
|
+
formData: args.form_data,
|
|
174
|
+
}),
|
|
175
|
+
),
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
return [
|
|
179
|
+
"run_workflow",
|
|
180
|
+
"get_workflow_execution",
|
|
181
|
+
"get_workflow_execution_events",
|
|
182
|
+
"list_pending_approvals",
|
|
183
|
+
"submit_workflow_task_approval",
|
|
184
|
+
];
|
|
71
185
|
}
|
|
72
186
|
|
|
73
187
|
/** Fetch a single workflow execution by id. */
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
// MCP tools for the Workflow domain (CRUD: get, apply, delete)
|
|
2
|
-
//
|
|
1
|
+
// MCP tools for the Workflow domain (CRUD: get, apply, delete) plus the
|
|
2
|
+
// versioning surface (version param on get, list_workflow_versions,
|
|
3
|
+
// tag_workflow_version). The CRUD names/descriptions are part of the original
|
|
4
|
+
// Go-parity contract (mcp-server/internal/domains/workflows/tools.go).
|
|
3
5
|
//
|
|
4
6
|
// The workflow-specific tools (validate_workflow_yaml, task-kind registry) live
|
|
5
7
|
// in sibling files.
|
|
@@ -13,22 +15,36 @@ import { textOrError } from "../toolresult.js";
|
|
|
13
15
|
import { applyWorkflow } from "./apply.js";
|
|
14
16
|
import { deleteWorkflow } from "./delete.js";
|
|
15
17
|
import { fetchWorkflow } from "./fetch.js";
|
|
18
|
+
import { fetchWorkflowVersion, listWorkflowVersions, tagWorkflowVersion } from "./versions.js";
|
|
16
19
|
|
|
17
20
|
/** Register the Workflow CRUD tools; returns the registered tool names. */
|
|
18
21
|
export function registerWorkflowTools(server: McpServer, target: BackendTarget): string[] {
|
|
19
22
|
server.registerTool(
|
|
20
23
|
"get_workflow",
|
|
21
24
|
{
|
|
22
|
-
description:
|
|
25
|
+
description:
|
|
26
|
+
"Get full details of a Stigmer workflow by its org and slug. Pass 'version' (a full " +
|
|
27
|
+
"SHA-256 version hash from list_workflow_versions) to fetch a historical version instead — " +
|
|
28
|
+
"that returns the version entry with its validated YAML rather than the live workflow. " +
|
|
29
|
+
"Tags are not accepted here; resolve a tag to its hash via list_workflow_versions first.",
|
|
23
30
|
inputSchema: {
|
|
24
31
|
org: z.string().describe("Organization slug that owns the workflow."),
|
|
25
32
|
slug: z.string().describe("Workflow slug — unique identifier within the org."),
|
|
33
|
+
version: z
|
|
34
|
+
.string()
|
|
35
|
+
.optional()
|
|
36
|
+
.describe(
|
|
37
|
+
"Full 64-character SHA-256 version hash of a historical version. Omit for the live workflow.",
|
|
38
|
+
),
|
|
26
39
|
},
|
|
27
40
|
},
|
|
28
41
|
(args, extra) =>
|
|
29
|
-
textOrError(() =>
|
|
30
|
-
|
|
31
|
-
|
|
42
|
+
textOrError(() => {
|
|
43
|
+
const token = resolveToken(extra, target.apiKey);
|
|
44
|
+
return args.version !== undefined && args.version !== ""
|
|
45
|
+
? fetchWorkflowVersion(target.serverAddress, token, args.org, args.slug, args.version)
|
|
46
|
+
: fetchWorkflow(target.serverAddress, token, args.org, args.slug);
|
|
47
|
+
}),
|
|
32
48
|
);
|
|
33
49
|
|
|
34
50
|
server.registerTool(
|
|
@@ -64,5 +80,72 @@ export function registerWorkflowTools(server: McpServer, target: BackendTarget):
|
|
|
64
80
|
),
|
|
65
81
|
);
|
|
66
82
|
|
|
67
|
-
|
|
83
|
+
server.registerTool(
|
|
84
|
+
"list_workflow_versions",
|
|
85
|
+
{
|
|
86
|
+
description:
|
|
87
|
+
"List a workflow's version history (newest first): version hash, tag, who applied it and " +
|
|
88
|
+
"when, and which version is current. Every apply that changes the workflow creates a new " +
|
|
89
|
+
"immutable version identified by its content hash. Entries omit the version YAML — fetch " +
|
|
90
|
+
"one version's full content with get_workflow and its hash.",
|
|
91
|
+
inputSchema: {
|
|
92
|
+
org: z.string().describe("Organization slug that owns the workflow."),
|
|
93
|
+
slug: z.string().describe("Workflow slug — unique identifier within the org."),
|
|
94
|
+
page_size: z
|
|
95
|
+
.number()
|
|
96
|
+
.int()
|
|
97
|
+
.optional()
|
|
98
|
+
.describe("Maximum versions per page (default 50, max 100)."),
|
|
99
|
+
page_token: z
|
|
100
|
+
.string()
|
|
101
|
+
.optional()
|
|
102
|
+
.describe("Pagination token from a previous response's next_page_token."),
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
(args, extra) =>
|
|
106
|
+
textOrError(() =>
|
|
107
|
+
listWorkflowVersions(target.serverAddress, resolveToken(extra, target.apiKey), {
|
|
108
|
+
org: args.org,
|
|
109
|
+
slug: args.slug,
|
|
110
|
+
pageSize: args.page_size,
|
|
111
|
+
pageToken: args.page_token,
|
|
112
|
+
}),
|
|
113
|
+
),
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
server.registerTool(
|
|
117
|
+
"tag_workflow_version",
|
|
118
|
+
{
|
|
119
|
+
description:
|
|
120
|
+
"Assign a tag (e.g. stable, production) to a specific workflow version. Tags are mutable " +
|
|
121
|
+
"pointers: re-tagging with an existing name moves it from its previous version, and a " +
|
|
122
|
+
"version holds at most one tag. Get version hashes from list_workflow_versions. Returns " +
|
|
123
|
+
"the updated workflow.",
|
|
124
|
+
inputSchema: {
|
|
125
|
+
org: z.string().describe("Organization slug that owns the workflow."),
|
|
126
|
+
slug: z.string().describe("Workflow slug — unique identifier within the org."),
|
|
127
|
+
version: z.string().describe("Full 64-character SHA-256 hash of the version to tag."),
|
|
128
|
+
tag: z
|
|
129
|
+
.string()
|
|
130
|
+
.describe("Tag to assign: alphanumeric with dots, hyphens, or underscores (e.g. stable, v1.0)."),
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
(args, extra) =>
|
|
134
|
+
textOrError(() =>
|
|
135
|
+
tagWorkflowVersion(target.serverAddress, resolveToken(extra, target.apiKey), {
|
|
136
|
+
org: args.org,
|
|
137
|
+
slug: args.slug,
|
|
138
|
+
versionHash: args.version,
|
|
139
|
+
tag: args.tag,
|
|
140
|
+
}),
|
|
141
|
+
),
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
return [
|
|
145
|
+
"get_workflow",
|
|
146
|
+
"apply_workflow",
|
|
147
|
+
"delete_workflow",
|
|
148
|
+
"list_workflow_versions",
|
|
149
|
+
"tag_workflow_version",
|
|
150
|
+
];
|
|
68
151
|
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// Workflow versioning paths: the version timeline (listVersions), a pinned
|
|
2
|
+
// historical version (getVersion, surfaced through get_workflow's optional
|
|
3
|
+
// version argument), and tag assignment (tagVersion).
|
|
4
|
+
//
|
|
5
|
+
// Version identity is the SHA-256 content hash of the validated CNCF YAML;
|
|
6
|
+
// tags are mutable pointers onto hashes. getVersion and tagVersion address by
|
|
7
|
+
// workflow ID + full hash — no tag or slug resolution server-side — so the
|
|
8
|
+
// tools here do the org/slug → ID two-step, and tag → hash mapping goes
|
|
9
|
+
// through the timeline (the tool descriptions teach the model that sequence).
|
|
10
|
+
//
|
|
11
|
+
// The timeline projection strips validated_yaml from every entry: the backend
|
|
12
|
+
// embeds each version's full workflow YAML, which would multiply a 50-entry
|
|
13
|
+
// page into 50 documents. The timeline answers "what versions exist"; the
|
|
14
|
+
// YAML of one version comes from get_workflow with that version's hash.
|
|
15
|
+
|
|
16
|
+
import { createClient } from "@connectrpc/connect";
|
|
17
|
+
import type { MessageInitShape } from "@bufbuild/protobuf";
|
|
18
|
+
import {
|
|
19
|
+
type ListWorkflowVersionsInputSchema,
|
|
20
|
+
ListWorkflowVersionsResponseSchema,
|
|
21
|
+
WorkflowVersionEntrySchema,
|
|
22
|
+
} from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/version_pb";
|
|
23
|
+
import { WorkflowSchema } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/api_pb";
|
|
24
|
+
import { WorkflowCommandController } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/command_pb";
|
|
25
|
+
import { WorkflowQueryController } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/query_pb";
|
|
26
|
+
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
27
|
+
|
|
28
|
+
import { withClient, withTransport } from "../client.js";
|
|
29
|
+
import { toProtoJson } from "../marshal.js";
|
|
30
|
+
import { rpcError } from "../rpcerr.js";
|
|
31
|
+
|
|
32
|
+
export interface ListWorkflowVersionsArgs {
|
|
33
|
+
readonly org: string;
|
|
34
|
+
readonly slug: string;
|
|
35
|
+
readonly pageSize?: number;
|
|
36
|
+
readonly pageToken?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* List a workflow's version history (newest first), with validated_yaml
|
|
41
|
+
* stripped from every entry (see file header).
|
|
42
|
+
*/
|
|
43
|
+
export async function listWorkflowVersions(
|
|
44
|
+
serverAddress: string,
|
|
45
|
+
token: string,
|
|
46
|
+
args: ListWorkflowVersionsArgs,
|
|
47
|
+
): Promise<string> {
|
|
48
|
+
return withClient(WorkflowQueryController, serverAddress, token, async (client, callOptions) => {
|
|
49
|
+
const req: MessageInitShape<typeof ListWorkflowVersionsInputSchema> = {
|
|
50
|
+
org: args.org,
|
|
51
|
+
slug: args.slug,
|
|
52
|
+
pageToken: args.pageToken ?? "",
|
|
53
|
+
};
|
|
54
|
+
// Forward page_size only when set, letting the server apply its default.
|
|
55
|
+
if ((args.pageSize ?? 0) > 0) {
|
|
56
|
+
req.pageSize = args.pageSize;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const resp = await client.listVersions(req, callOptions);
|
|
60
|
+
const data = JSON.parse(
|
|
61
|
+
toProtoJson(ListWorkflowVersionsResponseSchema, resp),
|
|
62
|
+
) as Record<string, unknown>;
|
|
63
|
+
if (Array.isArray(data.versions)) {
|
|
64
|
+
for (const entry of data.versions as Array<Record<string, unknown>>) {
|
|
65
|
+
delete entry.validated_yaml;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return JSON.stringify(data, null, 2);
|
|
69
|
+
} catch (err) {
|
|
70
|
+
throw rpcError(err, `versions of workflow "${args.slug}" in org "${args.org}"`);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Fetch one historical version of a workflow: resolve org/slug → ID, then
|
|
77
|
+
* getVersion by full hash. Returns the WorkflowVersionEntry (hash, tag,
|
|
78
|
+
* provenance, and the version's validated YAML) as protojson.
|
|
79
|
+
*/
|
|
80
|
+
export async function fetchWorkflowVersion(
|
|
81
|
+
serverAddress: string,
|
|
82
|
+
token: string,
|
|
83
|
+
org: string,
|
|
84
|
+
slug: string,
|
|
85
|
+
versionHash: string,
|
|
86
|
+
): Promise<string> {
|
|
87
|
+
const desc = `version "${versionHash}" of workflow "${slug}" in org "${org}"`;
|
|
88
|
+
return withTransport(serverAddress, token, async (transport, callOptions) => {
|
|
89
|
+
const query = createClient(WorkflowQueryController, transport);
|
|
90
|
+
try {
|
|
91
|
+
const workflow = await query.getByReference(
|
|
92
|
+
{ org, kind: ApiResourceKind.workflow, slug },
|
|
93
|
+
callOptions,
|
|
94
|
+
);
|
|
95
|
+
const entry = await query.getVersion(
|
|
96
|
+
{ workflowId: workflow.metadata?.id ?? "", versionHash },
|
|
97
|
+
callOptions,
|
|
98
|
+
);
|
|
99
|
+
return toProtoJson(WorkflowVersionEntrySchema, entry);
|
|
100
|
+
} catch (err) {
|
|
101
|
+
throw rpcError(err, desc);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface TagWorkflowVersionArgs {
|
|
107
|
+
readonly org: string;
|
|
108
|
+
readonly slug: string;
|
|
109
|
+
readonly versionHash: string;
|
|
110
|
+
readonly tag: string;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Assign (or move) a tag onto a workflow version: resolve org/slug → ID, then
|
|
115
|
+
* tagVersion. Returns the updated workflow as protojson.
|
|
116
|
+
*/
|
|
117
|
+
export async function tagWorkflowVersion(
|
|
118
|
+
serverAddress: string,
|
|
119
|
+
token: string,
|
|
120
|
+
args: TagWorkflowVersionArgs,
|
|
121
|
+
): Promise<string> {
|
|
122
|
+
const desc = `tag "${args.tag}" on workflow "${args.slug}" in org "${args.org}"`;
|
|
123
|
+
return withTransport(serverAddress, token, async (transport, callOptions) => {
|
|
124
|
+
const query = createClient(WorkflowQueryController, transport);
|
|
125
|
+
let id: string;
|
|
126
|
+
try {
|
|
127
|
+
const workflow = await query.getByReference(
|
|
128
|
+
{ org: args.org, kind: ApiResourceKind.workflow, slug: args.slug },
|
|
129
|
+
callOptions,
|
|
130
|
+
);
|
|
131
|
+
id = workflow.metadata?.id ?? "";
|
|
132
|
+
} catch (err) {
|
|
133
|
+
throw rpcError(err, desc);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const command = createClient(WorkflowCommandController, transport);
|
|
137
|
+
try {
|
|
138
|
+
const workflow = await command.tagVersion(
|
|
139
|
+
{ workflowId: id, versionHash: args.versionHash, tag: args.tag },
|
|
140
|
+
callOptions,
|
|
141
|
+
);
|
|
142
|
+
return toProtoJson(WorkflowSchema, workflow);
|
|
143
|
+
} catch (err) {
|
|
144
|
+
throw rpcError(err, desc);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}
|
package/src/gen/agent.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { generateSlug, visibilityFromString } from "./apply-runtime.js";
|
|
7
7
|
import { create } from "@bufbuild/protobuf";
|
|
8
8
|
import { AgentSchema, type Agent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
|
|
9
|
-
import { AgentSpecSchema, ToolApprovalOverrideSchema, McpServerUsageSchema, McpAccessSchema, SubAgentSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
|
|
9
|
+
import { AgentSpecSchema, ToolApprovalOverrideSchema, McpServerUsageSchema, McpAccessSchema, SubAgentSchema, DatastoreUsageSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
|
|
10
10
|
import { EnvVarDeclarationSchema } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/spec_pb";
|
|
11
11
|
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
12
12
|
import { ApiResourceReferenceSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/io_pb";
|
|
@@ -28,6 +28,7 @@ export const AgentInputShape = {
|
|
|
28
28
|
skill_refs: z.array(z.lazy(() => SkillRefInputSchema)).optional().describe("Skill resources providing additional knowledge to the agent."),
|
|
29
29
|
sub_agents: z.array(z.lazy(() => SubAgentInputSchema)).optional().describe("Sub-agents that can be delegated to. Sub-agents can access a subset of the parent's MCP servers and tools."),
|
|
30
30
|
env: z.record(z.lazy(() => EnvVarDeclarationInputSchema)).optional().describe("Environment variable declarations for this agent. Keys are variable names; values describe their metadata and optionality."),
|
|
31
|
+
datastore_usages: z.array(z.lazy(() => DatastoreUsageInputSchema)).optional().describe("Datastores this agent can use. Each entry must reference a Datastore resource by slug."),
|
|
31
32
|
} as const;
|
|
32
33
|
|
|
33
34
|
export const AgentInputSchema = z.object(AgentInputShape);
|
|
@@ -83,6 +84,17 @@ const EnvVarDeclarationInputSchema = z.object({
|
|
|
83
84
|
});
|
|
84
85
|
type EnvVarDeclarationInput = z.infer<typeof EnvVarDeclarationInputSchema>;
|
|
85
86
|
|
|
87
|
+
const DatastoreRefInputSchema = z.object({
|
|
88
|
+
org: z.string().optional().describe("Organization that owns the referenced resource. When non-empty: must be a valid org slug (lowercase alphanumeric with hyphens, starts with a letter, 1-63 characters). Example: 'stigmer', 'acme-corp'. When empty: the reference is relative — the server resolves it to the parent resource's organization at write time. All stored and returned references always have org populated (absolute form). Use empty org for same-org references (the common case). Use explicit org for cross-org references (e.g., marketplace resources)."),
|
|
89
|
+
slug: z.string().describe("Resource slug (user-friendly identifier, unique within org). Format: lowercase alphanumeric with hyphens, must start with a letter and end with a letter or digit (e.g., 'web-search', 'code-reviewer'). Length: 2-63 characters."),
|
|
90
|
+
});
|
|
91
|
+
type DatastoreRefInput = z.infer<typeof DatastoreRefInputSchema>;
|
|
92
|
+
|
|
93
|
+
const DatastoreUsageInputSchema = z.object({
|
|
94
|
+
datastore_ref: z.lazy(() => DatastoreRefInputSchema).describe("Reference to the Datastore resource."),
|
|
95
|
+
});
|
|
96
|
+
type DatastoreUsageInput = z.infer<typeof DatastoreUsageInputSchema>;
|
|
97
|
+
|
|
86
98
|
|
|
87
99
|
/** Build the fully-formed Agent proto from the flat MCP apply input. */
|
|
88
100
|
export function agentInputToProto(input: AgentInput): Agent {
|
|
@@ -97,6 +109,7 @@ export function agentInputToProto(input: AgentInput): Agent {
|
|
|
97
109
|
if (input.env !== undefined) {
|
|
98
110
|
for (const [k, v] of Object.entries(input.env)) spec.env[k] = envVarDeclarationInputToProto(v);
|
|
99
111
|
}
|
|
112
|
+
if (input.datastore_usages !== undefined) spec.datastoreUsages = input.datastore_usages.map(datastoreUsageInputToProto);
|
|
100
113
|
return Object.assign(create(AgentSchema), {
|
|
101
114
|
apiVersion: "agentic.stigmer.ai/v1",
|
|
102
115
|
kind: "Agent",
|
|
@@ -171,3 +184,17 @@ function envVarDeclarationInputToProto(input: EnvVarDeclarationInput) {
|
|
|
171
184
|
return result;
|
|
172
185
|
}
|
|
173
186
|
|
|
187
|
+
function datastoreRefInputToProto(input: DatastoreRefInput) {
|
|
188
|
+
return create(ApiResourceReferenceSchema, {
|
|
189
|
+
org: input.org,
|
|
190
|
+
slug: input.slug,
|
|
191
|
+
kind: ApiResourceKind.datastore,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function datastoreUsageInputToProto(input: DatastoreUsageInput) {
|
|
196
|
+
const result = create(DatastoreUsageSchema);
|
|
197
|
+
if (input.datastore_ref !== undefined) result.datastoreRef = datastoreRefInputToProto(input.datastore_ref);
|
|
198
|
+
return result;
|
|
199
|
+
}
|
|
200
|
+
|