@emseepea/create-progress-streaming-server 0.0.13 → 0.0.18
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 +34 -2
- package/initializer-dist/template/README.md +35 -3
- package/initializer-dist/template/eval/meaning.test.mjs +12 -3
- package/initializer-dist/template/package.json +4 -2
- package/initializer-dist/template/src/app.ts +21 -0
- package/initializer-dist/template/src/capabilities/tool.run-germination-trial.ts +10 -5
- package/initializer-dist/template/src/server.ts +5 -7
- package/initializer-dist/template/test/server.test.mjs +144 -1
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -17,12 +17,37 @@ npm init @emseepea/progress-streaming-server -- my-server
|
|
|
17
17
|
|
|
18
18
|
<!-- generated-project-readme -->
|
|
19
19
|
|
|
20
|
+
## Choose Open or Protected Access
|
|
21
|
+
|
|
22
|
+
Start open when the catalogue and operations are public.
|
|
23
|
+
|
|
24
|
+
To protect this template, pass both options to the app factory:
|
|
25
|
+
|
|
26
|
+
- `access: { access: "protected", requiredScopes: ["peas:read"] }`
|
|
27
|
+
- an `authentication` adapter
|
|
28
|
+
|
|
29
|
+
Keep `authentication.discovery` as `"public"` unless capability names or
|
|
30
|
+
schemas are sensitive. Use `"protected"` only when each principal should see a
|
|
31
|
+
permission-filtered catalogue. OAuth metadata remains public in both modes.
|
|
32
|
+
|
|
33
|
+
## Add Observability
|
|
34
|
+
|
|
35
|
+
The same factory accepts `observability`.
|
|
36
|
+
|
|
37
|
+
- Use `structuredLogging` for safe structured events.
|
|
38
|
+
- Use `openTelemetry` for traces and metrics.
|
|
39
|
+
|
|
40
|
+
Adapters receive only redacted framework events. They never receive request
|
|
41
|
+
bodies, arguments, results, tokens, provider claims, or raw errors. See the
|
|
42
|
+
[server API](https://github.com/emseepea/emseepea/tree/main/packages/framework#authentication-and-observability) for the complete configuration.
|
|
43
|
+
|
|
20
44
|
## Streaming Progress Example
|
|
21
45
|
|
|
22
46
|
Choose this example when a tool takes long enough that people benefit from
|
|
23
47
|
seeing progress before the final answer.
|
|
24
48
|
|
|
25
|
-
The
|
|
49
|
+
The tool reports progress during its request. It can use the public access shown
|
|
50
|
+
in the template or the protected access described above. A client can ask for
|
|
26
51
|
server-sent events (SSE), which carry progress over the same `POST` request.
|
|
27
52
|
Without that request, the tool returns one JSON response when it finishes.
|
|
28
53
|
|
|
@@ -39,11 +64,18 @@ npm start
|
|
|
39
64
|
The server listens on `http://127.0.0.1:3000/mcp` by default. Set `PORT` to
|
|
40
65
|
choose another port. This example starts locally and does not configure a proxy.
|
|
41
66
|
|
|
42
|
-
To adapt it for a
|
|
67
|
+
To adapt it for a deployed server, see
|
|
43
68
|
[Use Progress Behind a Proxy](https://github.com/emseepea/emseepea/blob/main/packages/framework/README.md#use-progress-behind-a-proxy).
|
|
44
69
|
It does not add saved sessions, replay, subscriptions, or recovery after
|
|
45
70
|
reconnecting.
|
|
46
71
|
|
|
72
|
+
## Add Feedback
|
|
73
|
+
|
|
74
|
+
Install `@emseepea/feedback` when this server needs a detailed one-way
|
|
75
|
+
observation or a durable support conversation. Pass its tools through the
|
|
76
|
+
application factory's `additionalTools` option. Choose PostgreSQL, Firestore,
|
|
77
|
+
GitHub Issues, or Zendesk in the [feedback guide](../../packages/feedback/README.md).
|
|
78
|
+
|
|
47
79
|
## Check This Example
|
|
48
80
|
|
|
49
81
|
[Ordinary tests](test/) live in `test/`.
|
|
@@ -1,9 +1,34 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Choose Open or Protected Access
|
|
2
|
+
|
|
3
|
+
Start open when the catalogue and operations are public.
|
|
4
|
+
|
|
5
|
+
To protect this template, pass both options to the app factory:
|
|
6
|
+
|
|
7
|
+
- `access: { access: "protected", requiredScopes: ["peas:read"] }`
|
|
8
|
+
- an `authentication` adapter
|
|
9
|
+
|
|
10
|
+
Keep `authentication.discovery` as `"public"` unless capability names or
|
|
11
|
+
schemas are sensitive. Use `"protected"` only when each principal should see a
|
|
12
|
+
permission-filtered catalogue. OAuth metadata remains public in both modes.
|
|
13
|
+
|
|
14
|
+
## Add Observability
|
|
15
|
+
|
|
16
|
+
The same factory accepts `observability`.
|
|
17
|
+
|
|
18
|
+
- Use `structuredLogging` for safe structured events.
|
|
19
|
+
- Use `openTelemetry` for traces and metrics.
|
|
20
|
+
|
|
21
|
+
Adapters receive only redacted framework events. They never receive request
|
|
22
|
+
bodies, arguments, results, tokens, provider claims, or raw errors. See the
|
|
23
|
+
[server API](https://github.com/emseepea/emseepea/tree/main/packages/framework#authentication-and-observability) for the complete configuration.
|
|
24
|
+
|
|
25
|
+
## Streaming Progress Example
|
|
2
26
|
|
|
3
27
|
Choose this example when a tool takes long enough that people benefit from
|
|
4
28
|
seeing progress before the final answer.
|
|
5
29
|
|
|
6
|
-
The
|
|
30
|
+
The tool reports progress during its request. It can use the public access shown
|
|
31
|
+
in the template or the protected access described above. A client can ask for
|
|
7
32
|
server-sent events (SSE), which carry progress over the same `POST` request.
|
|
8
33
|
Without that request, the tool returns one JSON response when it finishes.
|
|
9
34
|
|
|
@@ -20,11 +45,18 @@ npm start
|
|
|
20
45
|
The server listens on `http://127.0.0.1:3000/mcp` by default. Set `PORT` to
|
|
21
46
|
choose another port. This example starts locally and does not configure a proxy.
|
|
22
47
|
|
|
23
|
-
To adapt it for a
|
|
48
|
+
To adapt it for a deployed server, see
|
|
24
49
|
[Use Progress Behind a Proxy](https://github.com/emseepea/emseepea/blob/main/packages/framework/README.md#use-progress-behind-a-proxy).
|
|
25
50
|
It does not add saved sessions, replay, subscriptions, or recovery after
|
|
26
51
|
reconnecting.
|
|
27
52
|
|
|
53
|
+
## Add Feedback
|
|
54
|
+
|
|
55
|
+
Install `@emseepea/feedback` when this server needs a detailed one-way
|
|
56
|
+
observation or a durable support conversation. Pass its tools through the
|
|
57
|
+
application factory's `additionalTools` option. Choose PostgreSQL, Firestore,
|
|
58
|
+
GitHub Issues, or Zendesk in the [feedback guide](../../packages/feedback/README.md).
|
|
59
|
+
|
|
28
60
|
## Check This Example
|
|
29
61
|
|
|
30
62
|
[Ordinary tests](test/) live in `test/`.
|
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import test from "node:test";
|
|
2
2
|
import {
|
|
3
3
|
assertNoToolCalls,
|
|
4
|
+
assertNoNegativeFeedback,
|
|
4
5
|
assertResponseContains,
|
|
5
6
|
assertResponseMeaning,
|
|
6
|
-
|
|
7
|
+
assertToolCallsWithOptionalFeedback,
|
|
7
8
|
createConversation,
|
|
8
9
|
} from "@emseepea/testing/semantic";
|
|
9
10
|
|
|
11
|
+
const server = new URL(import.meta.resolve("@emseepea/feedback/testing-server"));
|
|
12
|
+
const environment = {
|
|
13
|
+
EMSEEPEA_EVAL_APP_MODULE: new URL("../dist/app.js", import.meta.url).href,
|
|
14
|
+
EMSEEPEA_EVAL_APP_FACTORY: "createProgressStreamingServer",
|
|
15
|
+
};
|
|
16
|
+
|
|
10
17
|
test("keeps progress stages distinct from the completed result", async (t) => {
|
|
11
18
|
const chat = await createConversation(t, {
|
|
12
|
-
server
|
|
19
|
+
server,
|
|
20
|
+
environment,
|
|
13
21
|
});
|
|
14
22
|
|
|
15
23
|
// The judge checks the important progress-versus-result distinction once.
|
|
@@ -18,7 +26,7 @@ test("keeps progress stages distinct from the completed result", async (t) => {
|
|
|
18
26
|
"Run the sample-tray pea germination trial. List its progress stages and final result.",
|
|
19
27
|
);
|
|
20
28
|
|
|
21
|
-
|
|
29
|
+
await assertToolCallsWithOptionalFeedback(response, [{
|
|
22
30
|
name: "run-germination-trial",
|
|
23
31
|
arguments: { tray: "sample-tray" },
|
|
24
32
|
}]);
|
|
@@ -34,4 +42,5 @@ test("keeps progress stages distinct from the completed result", async (t) => {
|
|
|
34
42
|
);
|
|
35
43
|
assertNoToolCalls(followUp);
|
|
36
44
|
assertResponseContains(followUp, "sow");
|
|
45
|
+
assertNoNegativeFeedback(response, followUp);
|
|
37
46
|
});
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
"lint": "oxlint src test eval"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"@emseepea/
|
|
17
|
+
"@emseepea/feedback": "0.2.0",
|
|
18
|
+
"@emseepea/testing": "0.9.3",
|
|
19
|
+
"@modelcontextprotocol/client": "2.0.0",
|
|
18
20
|
"@types/node": "24.13.3",
|
|
19
21
|
"typescript": "6.0.3",
|
|
20
22
|
"oxlint": "1.80.0"
|
|
@@ -24,7 +26,7 @@
|
|
|
24
26
|
},
|
|
25
27
|
"private": true,
|
|
26
28
|
"dependencies": {
|
|
27
|
-
"@emseepea/server": "0.
|
|
29
|
+
"@emseepea/server": "0.6.1",
|
|
28
30
|
"zod": "4.4.3"
|
|
29
31
|
}
|
|
30
32
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createEmseepea,
|
|
3
|
+
discoverCapabilities,
|
|
4
|
+
type AccessPolicy,
|
|
5
|
+
type EmseepeaExtensions,
|
|
6
|
+
} from "@emseepea/server";
|
|
7
|
+
|
|
8
|
+
export interface ProgressStreamingServerOptions extends EmseepeaExtensions {
|
|
9
|
+
readonly access?: AccessPolicy;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function createProgressStreamingServer(options: ProgressStreamingServerOptions = {}) {
|
|
13
|
+
const { access = { access: "public" }, ...extensions } = options;
|
|
14
|
+
return createEmseepea({
|
|
15
|
+
name: "emseepea-progress-streaming-server",
|
|
16
|
+
version: "0.0.0",
|
|
17
|
+
instructions: "Use run-germination-trial for the sample pea germination trial.",
|
|
18
|
+
...await discoverCapabilities(new URL("./capabilities/", import.meta.url), access),
|
|
19
|
+
...extensions,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { setTimeout as delay } from "node:timers/promises";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
defineStreamingTool,
|
|
4
|
+
type AccessPolicy,
|
|
5
|
+
type CapabilityModuleFactory,
|
|
6
|
+
type StreamingToolContext,
|
|
7
|
+
} from "@emseepea/server";
|
|
3
8
|
import { z } from "zod";
|
|
4
9
|
|
|
5
|
-
export default (() => defineStreamingTool({
|
|
10
|
+
export default ((access) => defineStreamingTool({
|
|
6
11
|
name: "run-germination-trial",
|
|
7
|
-
access
|
|
12
|
+
...access,
|
|
8
13
|
description: "Run a sample pea germination trial with bounded progress.",
|
|
9
14
|
inputSchema: z.object({
|
|
10
15
|
tray: z.literal("sample-tray").describe("Sample germination tray to test."),
|
|
@@ -17,7 +22,7 @@ export default (() => defineStreamingTool({
|
|
|
17
22
|
stages: z.tuple([z.literal("soak"), z.literal("sow"), z.literal("sprout")])
|
|
18
23
|
.describe("Trial stages completed in order."),
|
|
19
24
|
}),
|
|
20
|
-
async handler({ tray }, { reportProgress, signal }) {
|
|
25
|
+
async handler({ tray }, { reportProgress, signal }: StreamingToolContext) {
|
|
21
26
|
const stages: ["soak", "sow", "sprout"] = ["soak", "sow", "sprout"];
|
|
22
27
|
for (const [index, stage] of stages.entries()) {
|
|
23
28
|
await reportProgress({ progress: index + 1, total: stages.length, message: stage });
|
|
@@ -26,4 +31,4 @@ export default (() => defineStreamingTool({
|
|
|
26
31
|
const data = { tray, status: "complete" as const, germinatedSeeds: 8 as const, totalSeeds: 10 as const, stages };
|
|
27
32
|
return { data };
|
|
28
33
|
},
|
|
29
|
-
})) satisfies CapabilityModuleFactory
|
|
34
|
+
})) satisfies CapabilityModuleFactory<AccessPolicy>;
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { serveEmseepea } from "@emseepea/server";
|
|
2
|
+
import { createProgressStreamingServer } from "./app.js";
|
|
2
3
|
|
|
3
|
-
const running = await serveEmseepea(
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
instructions: "Use run-germination-trial for the sample pea germination trial.",
|
|
7
|
-
...await discoverCapabilities(new URL("./capabilities/", import.meta.url)),
|
|
8
|
-
}), { port: Number.parseInt(process.env.PORT ?? "3000", 10) });
|
|
4
|
+
const running = await serveEmseepea(await createProgressStreamingServer(), {
|
|
5
|
+
port: Number.parseInt(process.env.PORT ?? "3000", 10),
|
|
6
|
+
});
|
|
9
7
|
|
|
10
8
|
console.log(`Em See Pea progress-streaming-server example listening at ${running.url}`);
|
|
11
9
|
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
+
import { once } from "node:events";
|
|
3
|
+
import { createServer, request } from "node:http";
|
|
2
4
|
import test from "node:test";
|
|
3
5
|
|
|
4
|
-
import {
|
|
6
|
+
import { Client, StreamableHTTPClientTransport } from "@modelcontextprotocol/client";
|
|
7
|
+
import { serveEmseepea } from "@emseepea/server";
|
|
8
|
+
import {
|
|
9
|
+
insecureTestAuthentication,
|
|
10
|
+
startEmseepea,
|
|
11
|
+
startMcpServer,
|
|
12
|
+
} from "@emseepea/testing";
|
|
13
|
+
import { createProgressStreamingServer } from "../dist/app.js";
|
|
5
14
|
|
|
6
15
|
test("reports bounded progress before returning the final germination result", async (t) => {
|
|
7
16
|
const running = await startMcpServer(t, new URL("../dist/server.js", import.meta.url));
|
|
@@ -29,3 +38,137 @@ test("reports bounded progress before returning the final germination result", a
|
|
|
29
38
|
});
|
|
30
39
|
assert.equal(result.content[0].text, JSON.stringify(result.structuredContent));
|
|
31
40
|
});
|
|
41
|
+
|
|
42
|
+
test("the same template composes protected access and observability", async (t) => {
|
|
43
|
+
const events = [];
|
|
44
|
+
const permissions = ["trials:run"];
|
|
45
|
+
const running = await startEmseepea(t, await createProgressStreamingServer({
|
|
46
|
+
access: { access: "protected", requiredScopes: permissions },
|
|
47
|
+
authentication: insecureTestAuthentication(permissions),
|
|
48
|
+
observability: [{ id: "test-log", emit: (event) => events.push(event) }],
|
|
49
|
+
}));
|
|
50
|
+
const client = await running.connect("test-token");
|
|
51
|
+
const progress = [];
|
|
52
|
+
const result = await client.callTool(
|
|
53
|
+
{ name: "run-germination-trial", arguments: { tray: "sample-tray" } },
|
|
54
|
+
{ onprogress: (update) => progress.push(update) },
|
|
55
|
+
);
|
|
56
|
+
assert.deepEqual(progress.map(({ message }) => message), ["soak", "sow", "sprout"]);
|
|
57
|
+
assert.equal(result.structuredContent.status, "complete");
|
|
58
|
+
assert.ok(events.some(({ capability }) => capability === "run-germination-trial"));
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("protected progress crosses a trusted proxy through official and raw clients", async (t) => {
|
|
62
|
+
const permissions = ["trials:run"];
|
|
63
|
+
const backend = await serveEmseepea(await createProgressStreamingServer({
|
|
64
|
+
access: { access: "protected", requiredScopes: permissions },
|
|
65
|
+
authentication: insecureTestAuthentication(permissions, "public"),
|
|
66
|
+
deployment: {
|
|
67
|
+
mode: "production-behind-proxy",
|
|
68
|
+
trustedProxyAddresses: ["127.0.0.1"],
|
|
69
|
+
allowedAuthorities: ["test.example"],
|
|
70
|
+
allowedOrigins: ["https://test.example"],
|
|
71
|
+
rateLimit: { maxRequests: 20, windowMs: 1_000, maxClients: 1 },
|
|
72
|
+
},
|
|
73
|
+
}), { port: 0 });
|
|
74
|
+
const proxy = await startTrustedProxy(backend.url);
|
|
75
|
+
t.after(async () => {
|
|
76
|
+
proxy.closeAllConnections();
|
|
77
|
+
await new Promise((resolve) => proxy.close(resolve));
|
|
78
|
+
await backend.close();
|
|
79
|
+
});
|
|
80
|
+
const url = new URL(`http://127.0.0.1:${proxy.address().port}/mcp`);
|
|
81
|
+
|
|
82
|
+
const client = new Client(
|
|
83
|
+
{ name: "packed-progress-test", version: "0.0.0" },
|
|
84
|
+
{ versionNegotiation: { mode: { pin: "2026-07-28" } } },
|
|
85
|
+
);
|
|
86
|
+
try {
|
|
87
|
+
await client.connect(new StreamableHTTPClientTransport(url, {
|
|
88
|
+
requestInit: { headers: {
|
|
89
|
+
Accept: "application/json, text/event-stream",
|
|
90
|
+
Authorization: "Bearer official-token",
|
|
91
|
+
} },
|
|
92
|
+
}));
|
|
93
|
+
const progress = [];
|
|
94
|
+
const result = await client.callTool(
|
|
95
|
+
{ name: "run-germination-trial", arguments: { tray: "sample-tray" } },
|
|
96
|
+
{ onprogress: (update) => progress.push(update) },
|
|
97
|
+
);
|
|
98
|
+
assert.ok(proxy.requestBodies.some((body) => body.includes('"progressToken"')));
|
|
99
|
+
assert.equal(proxy.responseTypes.at(-1), "text/event-stream");
|
|
100
|
+
assert.deepEqual(progress.map(({ message }) => message), ["soak", "sow", "sprout"]);
|
|
101
|
+
assert.equal(result.structuredContent.tray, "sample-tray");
|
|
102
|
+
} finally {
|
|
103
|
+
await client.close();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const response = await fetch(url, rawCall("raw-token"));
|
|
107
|
+
assert.equal(response.status, 200);
|
|
108
|
+
assert.match(response.headers.get("content-type"), /^text\/event-stream/);
|
|
109
|
+
const messages = (await response.text()).trim().split("\n\n").map((frame) =>
|
|
110
|
+
JSON.parse(frame.slice(frame.indexOf("data: ") + 6)));
|
|
111
|
+
assert.deepEqual(messages.slice(0, -1).map(({ params }) => params.message), ["soak", "sow", "sprout"]);
|
|
112
|
+
assert.equal(messages.at(-1).result.structuredContent.tray, "sample-tray");
|
|
113
|
+
assert.doesNotMatch(JSON.stringify(messages), /raw-token/);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
async function startTrustedProxy(backendUrl) {
|
|
117
|
+
const requestBodies = [];
|
|
118
|
+
const responseTypes = [];
|
|
119
|
+
const proxy = createServer((incoming, outgoing) => {
|
|
120
|
+
const chunks = [];
|
|
121
|
+
incoming.on("data", (chunk) => chunks.push(chunk));
|
|
122
|
+
incoming.on("end", () => requestBodies.push(Buffer.concat(chunks).toString("utf8")));
|
|
123
|
+
const upstream = request(new URL(incoming.url, backendUrl), {
|
|
124
|
+
method: incoming.method,
|
|
125
|
+
headers: {
|
|
126
|
+
...incoming.headers,
|
|
127
|
+
host: "test.example",
|
|
128
|
+
"x-forwarded-for": "192.0.2.1",
|
|
129
|
+
"x-forwarded-proto": "https",
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
upstream.on("response", (response) => {
|
|
133
|
+
responseTypes.push(response.headers["content-type"]);
|
|
134
|
+
outgoing.writeHead(response.statusCode, response.headers);
|
|
135
|
+
response.pipe(outgoing);
|
|
136
|
+
});
|
|
137
|
+
upstream.on("error", () => outgoing.destroy());
|
|
138
|
+
incoming.pipe(upstream);
|
|
139
|
+
});
|
|
140
|
+
proxy.listen(0, "127.0.0.1");
|
|
141
|
+
await once(proxy, "listening");
|
|
142
|
+
proxy.requestBodies = requestBodies;
|
|
143
|
+
proxy.responseTypes = responseTypes;
|
|
144
|
+
return proxy;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function rawCall(token) {
|
|
148
|
+
return {
|
|
149
|
+
method: "POST",
|
|
150
|
+
headers: {
|
|
151
|
+
Accept: "application/json, text/event-stream",
|
|
152
|
+
Authorization: `Bearer ${token}`,
|
|
153
|
+
"Content-Type": "application/json",
|
|
154
|
+
"MCP-Protocol-Version": "2026-07-28",
|
|
155
|
+
"Mcp-Method": "tools/call",
|
|
156
|
+
"Mcp-Name": "run-germination-trial",
|
|
157
|
+
},
|
|
158
|
+
body: JSON.stringify({
|
|
159
|
+
jsonrpc: "2.0",
|
|
160
|
+
id: "raw-call",
|
|
161
|
+
method: "tools/call",
|
|
162
|
+
params: {
|
|
163
|
+
name: "run-germination-trial",
|
|
164
|
+
arguments: { tray: "sample-tray" },
|
|
165
|
+
_meta: {
|
|
166
|
+
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
|
|
167
|
+
"io.modelcontextprotocol/clientInfo": { name: "raw-progress-test", version: "0.0.0" },
|
|
168
|
+
"io.modelcontextprotocol/clientCapabilities": {},
|
|
169
|
+
progressToken: "raw-progress",
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
}),
|
|
173
|
+
};
|
|
174
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@emseepea/create-progress-streaming-server",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.18",
|
|
4
4
|
"description": "Create an Em See Pea server that streams tool progress.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -18,9 +18,11 @@
|
|
|
18
18
|
"prepack": "npm run build:initializer"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"@emseepea/
|
|
21
|
+
"@emseepea/feedback": "0.2.0",
|
|
22
|
+
"@emseepea/server": "0.6.1",
|
|
22
23
|
"zod": "4.4.3",
|
|
23
|
-
"@emseepea/testing": "0.
|
|
24
|
+
"@emseepea/testing": "0.9.3",
|
|
25
|
+
"@modelcontextprotocol/client": "2.0.0",
|
|
24
26
|
"@types/node": "24.13.3",
|
|
25
27
|
"typescript": "6.0.3",
|
|
26
28
|
"oxlint": "1.80.0"
|