@stigmer/mcp-server 3.34.0 → 3.36.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/cli/mcp-server-stigmer.d.ts.map +1 -1
- package/cli/mcp-server-stigmer.js +2 -2
- package/cli/mcp-server-stigmer.js.map +1 -1
- package/config.d.ts.map +1 -1
- package/config.js.map +1 -1
- package/domains/agentexecutions/approve.d.ts.map +1 -1
- package/domains/agentexecutions/approve.js.map +1 -1
- package/domains/agentexecutions/fetch.d.ts.map +1 -1
- package/domains/agentexecutions/fetch.js.map +1 -1
- package/domains/agentexecutions/run.d.ts.map +1 -1
- package/domains/agentexecutions/run.js.map +1 -1
- package/domains/agentexecutions/tools.d.ts.map +1 -1
- package/domains/agentexecutions/tools.js.map +1 -1
- package/domains/agents/apply.d.ts.map +1 -1
- package/domains/agents/apply.js.map +1 -1
- package/domains/agents/delete.d.ts.map +1 -1
- package/domains/agents/delete.js.map +1 -1
- package/domains/agents/fetch.d.ts.map +1 -1
- package/domains/agents/fetch.js.map +1 -1
- package/domains/agents/resources.d.ts.map +1 -1
- package/domains/agents/resources.js.map +1 -1
- package/domains/agents/tools.d.ts.map +1 -1
- package/domains/agents/tools.js.map +1 -1
- package/domains/apply-visibility.d.ts.map +1 -1
- package/domains/apply-visibility.js.map +1 -1
- package/domains/channels/calls.d.ts.map +1 -1
- package/domains/channels/calls.js.map +1 -1
- package/domains/channels/errors.d.ts.map +1 -1
- package/domains/channels/errors.js.map +1 -1
- package/domains/channels/tools.d.ts.map +1 -1
- package/domains/channels/tools.js.map +1 -1
- package/domains/client.d.ts.map +1 -1
- package/domains/client.js.map +1 -1
- package/domains/conversation/calls.d.ts.map +1 -1
- package/domains/conversation/calls.js.map +1 -1
- package/domains/conversation/errors.d.ts.map +1 -1
- package/domains/conversation/errors.js.map +1 -1
- package/domains/conversation/tools.d.ts.map +1 -1
- package/domains/conversation/tools.js.map +1 -1
- package/domains/environments/apply.d.ts.map +1 -1
- package/domains/environments/apply.js.map +1 -1
- package/domains/environments/delete.d.ts.map +1 -1
- package/domains/environments/delete.js.map +1 -1
- package/domains/environments/fetch.d.ts.map +1 -1
- package/domains/environments/fetch.js.map +1 -1
- package/domains/environments/resources.d.ts.map +1 -1
- package/domains/environments/resources.js.map +1 -1
- package/domains/environments/tools.d.ts.map +1 -1
- package/domains/environments/tools.js.map +1 -1
- package/domains/executions/cancel.d.ts.map +1 -1
- package/domains/executions/cancel.js.map +1 -1
- package/domains/executions/tools.d.ts.map +1 -1
- package/domains/executions/tools.js.map +1 -1
- package/domains/marshal.d.ts.map +1 -1
- package/domains/marshal.js.map +1 -1
- package/domains/mcpservers/apply.d.ts.map +1 -1
- package/domains/mcpservers/apply.js.map +1 -1
- package/domains/mcpservers/delete.d.ts.map +1 -1
- package/domains/mcpservers/delete.js.map +1 -1
- package/domains/mcpservers/fetch.d.ts.map +1 -1
- package/domains/mcpservers/fetch.js.map +1 -1
- package/domains/mcpservers/resources.d.ts.map +1 -1
- package/domains/mcpservers/resources.js.map +1 -1
- package/domains/mcpservers/tools.d.ts.map +1 -1
- package/domains/mcpservers/tools.js.map +1 -1
- package/domains/memory/calls.d.ts.map +1 -1
- package/domains/memory/calls.js.map +1 -1
- package/domains/memory/context.d.ts.map +1 -1
- package/domains/memory/context.js.map +1 -1
- package/domains/memory/errors.d.ts.map +1 -1
- package/domains/memory/errors.js.map +1 -1
- package/domains/memory/tools.d.ts.map +1 -1
- package/domains/memory/tools.js.map +1 -1
- package/domains/resourcehandler.d.ts.map +1 -1
- package/domains/resourcehandler.js.map +1 -1
- package/domains/resourceuri.d.ts.map +1 -1
- package/domains/resourceuri.js.map +1 -1
- package/domains/rpcerr.d.ts.map +1 -1
- package/domains/rpcerr.js.map +1 -1
- package/domains/search/tools.d.ts.map +1 -1
- package/domains/search/tools.js.map +1 -1
- package/domains/skills/delete.d.ts.map +1 -1
- package/domains/skills/delete.js.map +1 -1
- package/domains/skills/fetch.d.ts.map +1 -1
- package/domains/skills/fetch.js.map +1 -1
- package/domains/skills/resources.d.ts.map +1 -1
- package/domains/skills/resources.js.map +1 -1
- package/domains/skills/tools.d.ts.map +1 -1
- package/domains/skills/tools.js.map +1 -1
- package/domains/skills/versions.d.ts.map +1 -1
- package/domains/skills/versions.js.map +1 -1
- package/domains/toolresult.d.ts.map +1 -1
- package/domains/toolresult.js.map +1 -1
- package/domains/workflowexecutions/approvals.d.ts.map +1 -1
- package/domains/workflowexecutions/approvals.js.map +1 -1
- package/domains/workflowexecutions/run.d.ts.map +1 -1
- package/domains/workflowexecutions/run.js.map +1 -1
- package/domains/workflowexecutions/tools.d.ts.map +1 -1
- package/domains/workflowexecutions/tools.js.map +1 -1
- package/domains/workflows/apply.d.ts.map +1 -1
- package/domains/workflows/apply.js.map +1 -1
- package/domains/workflows/delete.d.ts.map +1 -1
- package/domains/workflows/delete.js.map +1 -1
- package/domains/workflows/fetch.d.ts.map +1 -1
- package/domains/workflows/fetch.js.map +1 -1
- package/domains/workflows/resources.d.ts.map +1 -1
- package/domains/workflows/resources.js.map +1 -1
- package/domains/workflows/taskkinds.d.ts.map +1 -1
- package/domains/workflows/taskkinds.js.map +1 -1
- package/domains/workflows/tools.d.ts.map +1 -1
- package/domains/workflows/tools.js.map +1 -1
- package/domains/workflows/validate.d.ts.map +1 -1
- package/domains/workflows/validate.js.map +1 -1
- package/domains/workflows/versions.d.ts.map +1 -1
- package/domains/workflows/versions.js.map +1 -1
- package/gen/agent.d.ts.map +1 -1
- package/gen/agent.js.map +1 -1
- package/gen/apply-runtime.d.ts.map +1 -1
- package/gen/apply-runtime.js.map +1 -1
- package/gen/environment.d.ts.map +1 -1
- package/gen/environment.js.map +1 -1
- package/gen/mcpserver.d.ts.map +1 -1
- package/gen/mcpserver.js.map +1 -1
- package/gen/workflow.d.ts.map +1 -1
- package/gen/workflow.js +2 -2
- package/gen/workflow.js.map +1 -1
- package/index.d.ts.map +1 -1
- package/index.js.map +1 -1
- package/logger.d.ts.map +1 -1
- package/logger.js.map +1 -1
- package/package.json +3 -3
- package/readiness.d.ts.map +1 -1
- package/readiness.js.map +1 -1
- package/server.d.ts.map +1 -1
- package/server.js.map +1 -1
- package/src/gen/workflow.ts +2 -2
- package/src/config.test.ts +0 -88
- package/src/domains/apply.integration.test.ts +0 -313
- package/src/domains/channels/channels.integration.test.ts +0 -272
- package/src/domains/channels/errors.test.ts +0 -52
- package/src/domains/conversation/conversation.integration.test.ts +0 -233
- package/src/domains/deletes.integration.test.ts +0 -147
- package/src/domains/executions.integration.test.ts +0 -376
- package/src/domains/memory/context.test.ts +0 -95
- package/src/domains/memory/errors.test.ts +0 -54
- package/src/domains/memory/memory.integration.test.ts +0 -253
- package/src/domains/reads.integration.test.ts +0 -163
- package/src/domains/resources.integration.test.ts +0 -157
- package/src/domains/resourceuri.test.ts +0 -104
- package/src/domains/rpcerr.test.ts +0 -62
- package/src/domains/search/search.integration.test.ts +0 -141
- package/src/domains/versions.integration.test.ts +0 -212
- package/src/domains/workflows/validate.integration.test.ts +0 -117
- package/src/domains/workflows/workflow-tools.integration.test.ts +0 -148
- package/src/http.integration.test.ts +0 -235
- package/src/readiness.test.ts +0 -90
- package/src/server.integration.test.ts +0 -82
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
// In-process integration test for the conversation roster (the
|
|
2
|
-
// channels.integration.test.ts pattern: real Connect backend with a
|
|
3
|
-
// stubbed conversation service, real MCP client over an in-memory
|
|
4
|
-
// transport).
|
|
5
|
-
//
|
|
6
|
-
// Verifies the DD-008 D-b / A14 / A15 contract surface:
|
|
7
|
-
// - the conversation-only roster is exactly escalate_to_human with a
|
|
8
|
-
// single `reason` argument (agent audience — identity is
|
|
9
|
-
// server-derived, so nothing else exists to send);
|
|
10
|
-
// - the success answer is the A15 fixed copy, never the RPC's
|
|
11
|
-
// ChannelConversation row, and claims nothing the platform cannot
|
|
12
|
-
// keep (no console claim until the T04+ surface renders attention);
|
|
13
|
-
// - the conversation-own error mapper passes domain messages verbatim
|
|
14
|
-
// as {error, code} JSON — including NOT_FOUND, this domain's
|
|
15
|
-
// deliberate addition — while transport errors delegate to the
|
|
16
|
-
// shared classifier;
|
|
17
|
-
// - the zod bounds mirror the protovalidate constraints, refusing an
|
|
18
|
-
// empty or over-budget reason before any RPC.
|
|
19
|
-
|
|
20
|
-
import { create } from "@bufbuild/protobuf";
|
|
21
|
-
import { Code, ConnectError, type ConnectRouter } from "@connectrpc/connect";
|
|
22
|
-
import { connectNodeAdapter } from "@connectrpc/connect-node";
|
|
23
|
-
import {
|
|
24
|
-
createServer as createHttp2Server,
|
|
25
|
-
type Http2Server,
|
|
26
|
-
type ServerHttp2Session,
|
|
27
|
-
} from "node:http2";
|
|
28
|
-
import type { AddressInfo } from "node:net";
|
|
29
|
-
|
|
30
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
31
|
-
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
|
|
32
|
-
import { ChannelConversationCommandController } from "@stigmer/protos/ai/stigmer/agentic/agentchannel/v1/conversation_command_pb";
|
|
33
|
-
import {
|
|
34
|
-
ChannelConversationSchema,
|
|
35
|
-
type EscalateConversationInput,
|
|
36
|
-
} from "@stigmer/protos/ai/stigmer/agentic/agentchannel/v1/conversation_io_pb";
|
|
37
|
-
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
38
|
-
|
|
39
|
-
import { configureLogger } from "../../logger";
|
|
40
|
-
import { CONVERSATION_ROUTE, createConversationServer } from "../../server";
|
|
41
|
-
|
|
42
|
-
configureLogger({ level: "error", format: "text" });
|
|
43
|
-
|
|
44
|
-
let backend: Http2Server;
|
|
45
|
-
let client: Client;
|
|
46
|
-
const openSessions = new Set<ServerHttp2Session>();
|
|
47
|
-
|
|
48
|
-
/** The next stubbed outcome; tests set this. */
|
|
49
|
-
let escalateResponse: () => ReturnType<typeof create<typeof ChannelConversationSchema>>;
|
|
50
|
-
|
|
51
|
-
/** Requests the stub captured (object property for closure narrowing). */
|
|
52
|
-
const captured: { escalate?: EscalateConversationInput } = {};
|
|
53
|
-
|
|
54
|
-
interface ToolResult {
|
|
55
|
-
content: Array<{ type: string; text?: string }>;
|
|
56
|
-
isError?: boolean;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async function escalate(args: Record<string, unknown>): Promise<ToolResult> {
|
|
60
|
-
return (await client.callTool({
|
|
61
|
-
name: "escalate_to_human",
|
|
62
|
-
arguments: args,
|
|
63
|
-
})) as ToolResult;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
beforeAll(async () => {
|
|
67
|
-
const routes = (router: ConnectRouter) => {
|
|
68
|
-
router.service(ChannelConversationCommandController, {
|
|
69
|
-
escalate: (req) => {
|
|
70
|
-
captured.escalate = req;
|
|
71
|
-
return escalateResponse();
|
|
72
|
-
},
|
|
73
|
-
});
|
|
74
|
-
};
|
|
75
|
-
backend = createHttp2Server(connectNodeAdapter({ routes }));
|
|
76
|
-
backend.on("session", (session) => {
|
|
77
|
-
openSessions.add(session);
|
|
78
|
-
session.on("close", () => openSessions.delete(session));
|
|
79
|
-
});
|
|
80
|
-
await new Promise<void>((resolve) => backend.listen(0, "127.0.0.1", resolve));
|
|
81
|
-
const port = (backend.address() as AddressInfo).port;
|
|
82
|
-
|
|
83
|
-
const mcp = createConversationServer({ serverAddress: `127.0.0.1:${port}`, apiKey: "" });
|
|
84
|
-
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
|
85
|
-
client = new Client({ name: "conversation-integration", version: "test" });
|
|
86
|
-
await Promise.all([mcp.connect(serverTransport), client.connect(clientTransport)]);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
afterAll(async () => {
|
|
90
|
-
await client?.close();
|
|
91
|
-
for (const session of openSessions) session.destroy();
|
|
92
|
-
await new Promise<void>((resolve) => backend.close(() => resolve()));
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
describe("conversation roster (DD-008 D-c / A14)", () => {
|
|
96
|
-
it("exposes exactly escalate_to_human with a single reason argument", async () => {
|
|
97
|
-
const { tools } = await client.listTools();
|
|
98
|
-
expect(tools.map((t) => t.name)).toEqual(["escalate_to_human"]);
|
|
99
|
-
|
|
100
|
-
// The conversation identity is server-derived from the session
|
|
101
|
-
// credential's channel labels (the DD-003 identity doctrine), so
|
|
102
|
-
// reason is the ONLY argument — a channel or conversation id here
|
|
103
|
-
// would be a caller-supplied identity the reach must never trust.
|
|
104
|
-
const properties = (tools[0].inputSchema as { properties?: Record<string, unknown> })
|
|
105
|
-
.properties;
|
|
106
|
-
expect(Object.keys(properties ?? {})).toEqual(["reason"]);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it("pins the cross-repo route string (the TOOL_CALL_LIMIT precedent)", () => {
|
|
110
|
-
// The runner's conversation-attachment.ts builds the URL
|
|
111
|
-
// independently (shared/conversation-attachment.ts and its route
|
|
112
|
-
// pin); a drift here strands every synthesized attachment on a 404.
|
|
113
|
-
expect(CONVERSATION_ROUTE).toBe("/conversation");
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
describe("the success answer is the A15 copy, not the row", () => {
|
|
118
|
-
it("sends the reason verbatim and answers with fixed copy", async () => {
|
|
119
|
-
escalateResponse = () =>
|
|
120
|
-
create(ChannelConversationSchema, {
|
|
121
|
-
agentChannelId: "agch_1",
|
|
122
|
-
conversationKey: "919000000001",
|
|
123
|
-
needsAttention: true,
|
|
124
|
-
attentionReason: "customer wants a refund decision",
|
|
125
|
-
});
|
|
126
|
-
captured.escalate = undefined;
|
|
127
|
-
|
|
128
|
-
const result = await escalate({ reason: "customer wants a refund decision" });
|
|
129
|
-
|
|
130
|
-
expect(result.isError).toBeFalsy();
|
|
131
|
-
const req = captured.escalate as EscalateConversationInput | undefined;
|
|
132
|
-
expect(req?.reason).toBe("customer wants a refund decision");
|
|
133
|
-
|
|
134
|
-
const text = result.content[0]?.text ?? "";
|
|
135
|
-
expect(text).toContain("recorded on this conversation");
|
|
136
|
-
// A15: the answer instructs against the promise at the moment of
|
|
137
|
-
// temptation — the model's next message to the customer.
|
|
138
|
-
expect(text).toContain("do not");
|
|
139
|
-
// The row must never leak back: its control state and conversation
|
|
140
|
-
// key are internal, and reflecting them invites the model to
|
|
141
|
-
// narrate platform state to the customer.
|
|
142
|
-
expect(text).not.toContain("919000000001");
|
|
143
|
-
expect(text).not.toContain("needs_attention");
|
|
144
|
-
// No console surface renders attention yet (T04+); the copy must
|
|
145
|
-
// not claim one. Delete this pin when the Conversations surface
|
|
146
|
-
// ships and the copy gains the claim.
|
|
147
|
-
expect(text.toLowerCase()).not.toContain("console");
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
describe("zod bounds mirror the protovalidate constraints", () => {
|
|
152
|
-
it("refuses an empty and an over-budget reason before any RPC", async () => {
|
|
153
|
-
captured.escalate = undefined;
|
|
154
|
-
|
|
155
|
-
const empty = await escalate({ reason: "" });
|
|
156
|
-
expect(empty.isError).toBe(true);
|
|
157
|
-
|
|
158
|
-
const overBudget = await escalate({ reason: "x".repeat(1025) });
|
|
159
|
-
expect(overBudget.isError).toBe(true);
|
|
160
|
-
|
|
161
|
-
expect(captured.escalate).toBeUndefined();
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
describe("conversation error mapper", () => {
|
|
166
|
-
it("passes a reach denial through verbatim — never the shared rewrite", async () => {
|
|
167
|
-
escalateResponse = () => {
|
|
168
|
-
throw new ConnectError(
|
|
169
|
-
"escalate is agent-audience only: it requires a session-scoped runner credential",
|
|
170
|
-
Code.PermissionDenied,
|
|
171
|
-
);
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
const result = await escalate({ reason: "needs a human" });
|
|
175
|
-
|
|
176
|
-
expect(result.isError).toBe(true);
|
|
177
|
-
expect(JSON.parse(result.content[0]?.text ?? "{}")).toEqual({
|
|
178
|
-
error: "escalate is agent-audience only: it requires a session-scoped runner credential",
|
|
179
|
-
code: "PERMISSION_DENIED",
|
|
180
|
-
});
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
it("passes the OSS refusal through verbatim as FAILED_PRECONDITION", async () => {
|
|
184
|
-
escalateResponse = () => {
|
|
185
|
-
throw new ConnectError(
|
|
186
|
-
"conversation participation requires Stigmer Cloud",
|
|
187
|
-
Code.FailedPrecondition,
|
|
188
|
-
);
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
const result = await escalate({ reason: "needs a human" });
|
|
192
|
-
|
|
193
|
-
expect(result.isError).toBe(true);
|
|
194
|
-
expect(JSON.parse(result.content[0]?.text ?? "{}")).toEqual({
|
|
195
|
-
error: "conversation participation requires Stigmer Cloud",
|
|
196
|
-
code: "FAILED_PRECONDITION",
|
|
197
|
-
});
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
it("passes NOT_FOUND through verbatim — this domain's deliberate addition", async () => {
|
|
201
|
-
// The shared classifier rewrites NotFound into "Verify the org and
|
|
202
|
-
// slug are correct" — advice naming arguments escalate does not
|
|
203
|
-
// take. The domain set includes NotFound so the handler's honest
|
|
204
|
-
// answer reaches the model.
|
|
205
|
-
escalateResponse = () => {
|
|
206
|
-
throw new ConnectError(
|
|
207
|
-
"no conversation with this key exists on channel agch_1",
|
|
208
|
-
Code.NotFound,
|
|
209
|
-
);
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
const result = await escalate({ reason: "needs a human" });
|
|
213
|
-
|
|
214
|
-
expect(result.isError).toBe(true);
|
|
215
|
-
expect(JSON.parse(result.content[0]?.text ?? "{}")).toEqual({
|
|
216
|
-
error: "no conversation with this key exists on channel agch_1",
|
|
217
|
-
code: "NOT_FOUND",
|
|
218
|
-
});
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
it("delegates transport codes to the shared classifier", async () => {
|
|
222
|
-
escalateResponse = () => {
|
|
223
|
-
throw new ConnectError("upstream down", Code.Unavailable);
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
const result = await escalate({ reason: "needs a human" });
|
|
227
|
-
|
|
228
|
-
expect(result.isError).toBe(true);
|
|
229
|
-
expect(result.content[0]?.text).toBe(
|
|
230
|
-
"Stigmer server is unavailable. Ensure it is running and reachable.",
|
|
231
|
-
);
|
|
232
|
-
});
|
|
233
|
-
});
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
// In-process integration test for the delete tools. Verifies the two-step
|
|
2
|
-
// resolve→delete flow forwards the resolved id into the correct per-domain
|
|
3
|
-
// delete-input shape: typed {value} for agent/skill/workflow, and
|
|
4
|
-
// ApiResourceDeleteInput {resource_id} for mcp_server and environment.
|
|
5
|
-
|
|
6
|
-
import { create, toJson } from "@bufbuild/protobuf";
|
|
7
|
-
import type { ConnectRouter } from "@connectrpc/connect";
|
|
8
|
-
import { connectNodeAdapter } from "@connectrpc/connect-node";
|
|
9
|
-
import {
|
|
10
|
-
createServer as createHttp2Server,
|
|
11
|
-
type Http2Server,
|
|
12
|
-
type ServerHttp2Session,
|
|
13
|
-
} from "node:http2";
|
|
14
|
-
import type { AddressInfo } from "node:net";
|
|
15
|
-
|
|
16
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
17
|
-
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
|
|
18
|
-
import { AgentSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
|
|
19
|
-
import { AgentCommandController } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/command_pb";
|
|
20
|
-
import { AgentQueryController } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/query_pb";
|
|
21
|
-
import { EnvironmentSchema } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/api_pb";
|
|
22
|
-
import { EnvironmentCommandController } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/command_pb";
|
|
23
|
-
import { EnvironmentQueryController } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/query_pb";
|
|
24
|
-
import { McpServerSchema } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
|
|
25
|
-
import { McpServerCommandController } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/command_pb";
|
|
26
|
-
import { McpServerQueryController } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/query_pb";
|
|
27
|
-
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
28
|
-
|
|
29
|
-
import { configureLogger } from "../logger";
|
|
30
|
-
import { createServer } from "../server";
|
|
31
|
-
|
|
32
|
-
configureLogger({ level: "error", format: "text" });
|
|
33
|
-
|
|
34
|
-
const resolvedAgent = create(AgentSchema, {
|
|
35
|
-
apiVersion: "v1",
|
|
36
|
-
kind: "agent",
|
|
37
|
-
metadata: { name: "Code Reviewer", slug: "code-reviewer", org: "acme", id: "agt-123" },
|
|
38
|
-
});
|
|
39
|
-
const resolvedMcpServer = create(McpServerSchema, {
|
|
40
|
-
apiVersion: "v1",
|
|
41
|
-
kind: "mcp_server",
|
|
42
|
-
metadata: { name: "GitHub", slug: "github", org: "acme", id: "mcp-456" },
|
|
43
|
-
});
|
|
44
|
-
const resolvedEnvironment = create(EnvironmentSchema, {
|
|
45
|
-
apiVersion: "v1",
|
|
46
|
-
kind: "environment",
|
|
47
|
-
metadata: { name: "GitHub Creds", slug: "github-creds", org: "acme", id: "env-789" },
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
let backend: Http2Server;
|
|
51
|
-
let client: Client;
|
|
52
|
-
let deletedAgentId: string | undefined;
|
|
53
|
-
let deletedMcpResourceId: string | undefined;
|
|
54
|
-
let deletedEnvironmentResourceId: string | undefined;
|
|
55
|
-
const openSessions = new Set<ServerHttp2Session>();
|
|
56
|
-
|
|
57
|
-
interface ToolResult {
|
|
58
|
-
content: Array<{ type: string; text?: string }>;
|
|
59
|
-
isError?: boolean;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async function callTool(name: string, args: Record<string, unknown>): Promise<ToolResult> {
|
|
63
|
-
return (await client.callTool({ name, arguments: args })) as ToolResult;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
beforeAll(async () => {
|
|
67
|
-
const routes = (router: ConnectRouter) => {
|
|
68
|
-
router.service(AgentQueryController, { getByReference: () => resolvedAgent });
|
|
69
|
-
router.service(AgentCommandController, {
|
|
70
|
-
delete: (req) => {
|
|
71
|
-
deletedAgentId = req.value;
|
|
72
|
-
return resolvedAgent;
|
|
73
|
-
},
|
|
74
|
-
});
|
|
75
|
-
router.service(McpServerQueryController, { getByReference: () => resolvedMcpServer });
|
|
76
|
-
router.service(McpServerCommandController, {
|
|
77
|
-
delete: (req) => {
|
|
78
|
-
deletedMcpResourceId = req.resourceId;
|
|
79
|
-
return resolvedMcpServer;
|
|
80
|
-
},
|
|
81
|
-
});
|
|
82
|
-
router.service(EnvironmentQueryController, { getByReference: () => resolvedEnvironment });
|
|
83
|
-
router.service(EnvironmentCommandController, {
|
|
84
|
-
delete: (req) => {
|
|
85
|
-
deletedEnvironmentResourceId = req.resourceId;
|
|
86
|
-
return resolvedEnvironment;
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
};
|
|
90
|
-
backend = createHttp2Server(connectNodeAdapter({ routes }));
|
|
91
|
-
backend.on("session", (session) => {
|
|
92
|
-
openSessions.add(session);
|
|
93
|
-
session.on("close", () => openSessions.delete(session));
|
|
94
|
-
});
|
|
95
|
-
await new Promise<void>((resolve) => backend.listen(0, "127.0.0.1", resolve));
|
|
96
|
-
const port = (backend.address() as AddressInfo).port;
|
|
97
|
-
|
|
98
|
-
const mcp = createServer({ serverAddress: `127.0.0.1:${port}`, apiKey: "" });
|
|
99
|
-
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
|
100
|
-
client = new Client({ name: "deletes-integration", version: "test" });
|
|
101
|
-
await Promise.all([mcp.connect(serverTransport), client.connect(clientTransport)]);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
afterAll(async () => {
|
|
105
|
-
await client?.close();
|
|
106
|
-
for (const session of openSessions) session.destroy();
|
|
107
|
-
await new Promise<void>((resolve) => backend.close(() => resolve()));
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
describe("delete tools integration", () => {
|
|
111
|
-
it("advertises every delete tool", async () => {
|
|
112
|
-
const { tools } = await client.listTools();
|
|
113
|
-
expect(tools.map((t) => t.name)).toEqual(
|
|
114
|
-
expect.arrayContaining([
|
|
115
|
-
"delete_agent",
|
|
116
|
-
"delete_skill",
|
|
117
|
-
"delete_workflow",
|
|
118
|
-
"delete_mcp_server",
|
|
119
|
-
"delete_environment",
|
|
120
|
-
]),
|
|
121
|
-
);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it("delete_agent resolves the id then deletes via the typed AgentId", async () => {
|
|
125
|
-
const result = await callTool("delete_agent", { org: "acme", slug: "code-reviewer" });
|
|
126
|
-
expect(result.isError).toBeFalsy();
|
|
127
|
-
expect(deletedAgentId).toBe("agt-123");
|
|
128
|
-
expect(JSON.parse(result.content[0]?.text ?? "{}")).toEqual(
|
|
129
|
-
toJson(AgentSchema, resolvedAgent, { useProtoFieldName: true }),
|
|
130
|
-
);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it("delete_mcp_server resolves the id then deletes via ApiResourceDeleteInput", async () => {
|
|
134
|
-
const result = await callTool("delete_mcp_server", { org: "acme", slug: "github" });
|
|
135
|
-
expect(result.isError).toBeFalsy();
|
|
136
|
-
expect(deletedMcpResourceId).toBe("mcp-456");
|
|
137
|
-
expect(JSON.parse(result.content[0]?.text ?? "{}")).toEqual(
|
|
138
|
-
toJson(McpServerSchema, resolvedMcpServer, { useProtoFieldName: true }),
|
|
139
|
-
);
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it("delete_environment resolves the id then deletes via ApiResourceDeleteInput", async () => {
|
|
143
|
-
const result = await callTool("delete_environment", { org: "acme", slug: "github-creds" });
|
|
144
|
-
expect(result.isError).toBeFalsy();
|
|
145
|
-
expect(deletedEnvironmentResourceId).toBe("env-789");
|
|
146
|
-
});
|
|
147
|
-
});
|