@savvy-web/mcp 3.4.19 → 3.4.20

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/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { BiomeFailed, EngineError, McpToolError, WorkspaceNotFound } from "./errors.js";
2
2
  import { makeSilkRuntimeLayer } from "./runtime.js";
3
+ import { ServerLayer } from "./server.js";
3
4
  import { SilkToolkit, ToolsLayer } from "./toolkit.js";
4
5
  import { CURRENT_MCP_VERSION } from "./version.js";
5
- import { ServerLayer } from "./server.js";
6
6
 
7
7
  export { BiomeFailed, CURRENT_MCP_VERSION, EngineError, McpToolError, ServerLayer, SilkToolkit, ToolsLayer, WorkspaceNotFound, makeSilkRuntimeLayer };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@savvy-web/mcp",
3
- "version": "3.4.19",
3
+ "version": "3.4.20",
4
4
  "private": false,
5
5
  "description": "The savvy MCP server — Silk Suite tooling and library knowledge for coding agents",
6
6
  "homepage": "https://github.com/savvy-web/systems/tree/main/packages/mcp",
@@ -36,14 +36,14 @@
36
36
  "savvy-mcp": "bin/savvy-mcp.js"
37
37
  },
38
38
  "dependencies": {
39
- "@effect/platform-node": "^4.0.7",
40
- "@effected/commands": "^0.18.0",
41
- "@effected/engine": "^0.10.0",
42
- "@effected/git": "^0.27.0",
43
- "@effected/mcp": "^0.11.0",
44
- "@effected/templates": "^0.15.0",
45
- "@effected/workspaces": "^0.40.0",
46
- "@savvy-web/silk-effects": "^10.2.1",
47
- "effect": "^4.0.7"
39
+ "@effect/platform-node": "~4.1.1",
40
+ "@effected/commands": "^0.19.0",
41
+ "@effected/engine": "^0.11.0",
42
+ "@effected/git": "^0.29.0",
43
+ "@effected/mcp": "^0.12.0",
44
+ "@effected/templates": "^0.16.0",
45
+ "@effected/workspaces": "^0.41.0",
46
+ "@savvy-web/silk-effects": "^11.0.0",
47
+ "effect": "~4.1.1"
48
48
  }
49
49
  }
package/server.js CHANGED
@@ -2,8 +2,9 @@ import { makeSilkRuntimeLayer } from "./runtime.js";
2
2
  import { SilkToolkit, ToolsLayer } from "./toolkit.js";
3
3
  import { CURRENT_MCP_VERSION } from "./version.js";
4
4
  import { McpStdio, McpToolkit } from "@effected/mcp";
5
- import { Layer, Option } from "effect";
5
+ import { Effect, Layer, Option } from "effect";
6
6
  import { distributionSuffix } from "@effected/engine";
7
+ import { McpServer } from "effect/ai";
7
8
 
8
9
  // src/server.ts
9
10
  /**
@@ -26,12 +27,31 @@ const SERVER_INSTRUCTIONS = [
26
27
  "Every successful result is a typed object in structuredContent (content[0].text carries the same object as JSON). A failure is an isError result whose content[0].text carries the message and remediation, with no structuredContent. Every tool takes an optional cwd; omit it to use the server's project directory."
27
28
  ].join("\n");
28
29
  /**
29
- * The toolkit registration as a layer: `McpToolkit.layer` over core's
30
- * module-level `McpServer.McpServer.layer` — the same reference
31
- * `McpStdio.layer` serves, so layer memoization lands the registration on the
32
- * served instance — with the handlers bound to `cwd`.
30
+ * Discharges every tool's declared `dependencies`. Since effect 4.1 a service a
31
+ * tool lists in `dependencies` is a per-request `McpRequest<"Requires", S>`
32
+ * requirement that only MCP middleware or the transport can meet;
33
+ * `Layer.provide` no longer does. The silk runtime is built ONCE (it holds the
34
+ * process-lifetime `ConfigInspector`, #229), so the middleware captures its
35
+ * context when the layer is built and provides that same context to every
36
+ * request.
37
+ *
38
+ * `Effect.context` captures the whole layer-build context, not only
39
+ * `McpServices` (also `Scope`, `Clock`, `Console`, `McpServer`, the memo map),
40
+ * and `Effect.provideContext` merges it OVER the request's context. Probed on
41
+ * 4.1.1: a handler finalizer still runs at the end of its own request, and no
42
+ * request-scoped key (`McpRequestContext`, log level, parent span) is in the
43
+ * build context today. Core's own registration capture filters those keys
44
+ * (`omitRequestServices`); this capture does not, so do not build this layer
45
+ * inside a span or under a request-level reference.
46
+ */
47
+ const RuntimeMiddleware = McpServer.middleware()(Effect.map(Effect.context(), (context) => (effect) => Effect.provideContext(effect, context)));
48
+ /**
49
+ * The toolkit registration as a layer: `McpToolkit.layer` with the handlers
50
+ * bound to `cwd` and {@link RuntimeMiddleware} meeting their request-level
51
+ * dependencies. Passed to `McpStdio.layer` as `registrations`, so it builds
52
+ * before the first request.
33
53
  */
34
- const SilkToolsLayer = (cwd) => McpToolkit.layer(SilkToolkit, { strict: "annotated" }).pipe(Layer.provide(ToolsLayer(cwd)));
54
+ const SilkToolsLayer = (cwd) => McpToolkit.layer(SilkToolkit, { strict: "annotated" }).pipe(Layer.provide(ToolsLayer(cwd)), Layer.provide(RuntimeMiddleware.layer));
35
55
  /**
36
56
  * The whole server as one layer: the ten-tool toolkit, the silk-effects
37
57
  * runtime discharging its dependencies, over `@effected/mcp`'s
@@ -44,11 +64,12 @@ const SilkToolsLayer = (cwd) => McpToolkit.layer(SilkToolkit, { strict: "annotat
44
64
  *
45
65
  * @public
46
66
  */
47
- const ServerLayer = (cwd, options = {}) => SilkToolsLayer(cwd).pipe(Layer.provide(makeSilkRuntimeLayer(cwd)), Layer.provide(McpStdio.layer({
67
+ const ServerLayer = (cwd, options = {}) => McpStdio.layer({
48
68
  name: "savvy-mcp",
49
69
  version: `${CURRENT_MCP_VERSION}${distributionSuffix(Option.fromNullishOr(options.distribution))}`,
50
70
  description: "Structured Silk Suite workspace tools: workspace, turbo, biome, changesets and vendored repos.",
51
- instructions: SERVER_INSTRUCTIONS
52
- })));
71
+ instructions: SERVER_INSTRUCTIONS,
72
+ registrations: SilkToolsLayer(cwd)
73
+ }).pipe(Layer.provide(makeSilkRuntimeLayer(cwd)));
53
74
 
54
75
  export { SERVER_INSTRUCTIONS, ServerLayer };
@@ -71,8 +71,8 @@ const GitlabDiagnostic = Schema.Struct({
71
71
  lines: Schema.Struct({ begin: Schema.Number })
72
72
  })
73
73
  });
74
- const GitlabArray = Schema.Array(GitlabDiagnostic);
75
- const decodeGitlab = Schema.decodeUnknownSync(GitlabArray);
74
+ /** Biome's gitlab stdout, parsed and decoded in one step; `None` for non-JSON or a shape mismatch. */
75
+ const decodeGitlab = Schema.decodeUnknownOption(Schema.fromJsonString(Schema.Array(GitlabDiagnostic)));
76
76
  /**
77
77
  * Map a gitlab severity back onto the Biome severity it was produced from.
78
78
  *
@@ -91,19 +91,9 @@ const mapSeverity = (s) => s === "info" || s === "minor" ? "info" : s === "major
91
91
  const parseBiomeGitlab = (stdout) => {
92
92
  const trimmed = stdout.trim();
93
93
  if (!trimmed) return [];
94
- let raw;
95
- try {
96
- raw = JSON.parse(trimmed);
97
- } catch {
98
- return [];
99
- }
100
- let decoded;
101
- try {
102
- decoded = decodeGitlab(raw);
103
- } catch {
104
- return [];
105
- }
106
- return decoded.map((d) => ({
94
+ const decoded = decodeGitlab(trimmed);
95
+ if (Option.isNone(decoded)) return [];
96
+ return decoded.value.map((d) => ({
107
97
  file: d.location.path,
108
98
  line: d.location.lines.begin,
109
99
  severity: mapSeverity(d.severity),
package/version.js CHANGED
@@ -6,6 +6,6 @@
6
6
  *
7
7
  * @packageDocumentation
8
8
  */
9
- const CURRENT_MCP_VERSION = "3.4.19";
9
+ const CURRENT_MCP_VERSION = "3.4.20";
10
10
 
11
11
  export { CURRENT_MCP_VERSION };