@gjermundgaraba/effect-actions 0.18.1 → 0.18.2

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.
@@ -97,7 +97,7 @@ type CallServices<C, A extends Any> = C extends Effect.Effect<infer M, unknown,
97
97
  * `Command.withSubcommands` on the result would put in the derived ones' place. `remote` calls a
98
98
  * server instead. A test runs it in memory, with no process:
99
99
  * `Command.runWith(command, { version })(args)`.
100
- * Guide: `docs/ActionCli.md` in this package; in an application: `examples/notes-service/src/commands.ts`.
100
+ * Guide: `docs/ActionCli.md` in this package; in an application: `examples/assistant/src/commands.ts`.
101
101
  */
102
102
  export declare function make<const Apps extends Served, const O extends Selection<ActionOf<Member<Apps>>> = {}, const Own extends Subcommands = []>(implementations: Apps, options: O & NoInfer<Options$1<ActionOf<Member<Apps>>>> & NoInfer<KnownOptions<O, Options$1, ActionOf<Member<Apps>>>> & {
103
103
  readonly subcommands?: Own | undefined;
@@ -86,7 +86,7 @@ function remoteCommand(binding, action, options) {
86
86
  * `Command.withSubcommands` on the result would put in the derived ones' place. `remote` calls a
87
87
  * server instead. A test runs it in memory, with no process:
88
88
  * `Command.runWith(command, { version })(args)`.
89
- * Guide: `docs/ActionCli.md` in this package; in an application: `examples/notes-service/src/commands.ts`.
89
+ * Guide: `docs/ActionCli.md` in this package; in an application: `examples/assistant/src/commands.ts`.
90
90
  */
91
91
  function make(implementations, options) {
92
92
  const apps = toList(implementations);
@@ -112,12 +112,13 @@ export declare function layer<const H extends AnyHttp, const Apps extends Served
112
112
  * `transformClient: HttpClient.mapRequest(HttpClientRequest.bearerToken(token))`. The native
113
113
  * client itself stays available: `HttpApiClient.make(Http.api)`.
114
114
  *
115
- * A call fails with a declared error value (the action's own, or a built-in
116
- * `InvalidInput`, `Unauthenticated` or `Forbidden`), a native `HttpClientError` when the
117
- * server could not be reached or answered with a status or body the contract does not
118
- * declare, or a `SchemaError` when the success does not decode. An input that does not encode
119
- * fails with `InvalidInput`, and nothing is sent. A call also fails with what the client
120
- * `transformClient` returns fails with, as it is, and requires what that client requires.
115
+ * A call fails with a declared error value (the action's own, the binding's, a built-in
116
+ * `InvalidInput`, `Unauthenticated` or `Forbidden`, or on a protected action its descriptor's),
117
+ * a native `HttpClientError` when the server could not be reached or answered with a status or
118
+ * body the contract does not declare, or a `SchemaError` when the success does not decode. An
119
+ * input that does not encode fails with `InvalidInput`, and nothing is sent. A call also fails
120
+ * with what the client `transformClient` returns fails with, as it is, and requires what that
121
+ * client requires.
121
122
  */
122
123
  export declare function client<const H extends AnyHttp>(binding: H, options?: Options): Effect.Effect<Client<H>, never, HttpClient.HttpClient>;
123
124
  export declare function client<const H extends AnyHttp, E, R>(binding: H, options: Options<E, R>): Effect.Effect<Client<H, E, R>, never, HttpClient.HttpClient>;
@@ -41,8 +41,8 @@ export interface ProtectedResource {
41
41
  export interface RefusalResponseOptions<D extends Any = Any> {
42
42
  /**
43
43
  * The descriptor refusing, whose scheme decides the challenge: Bearer's, below, when left
44
- * out; another scheme's 401 names that scheme, and nothing steps up under it. An error it
45
- * declares is sent as its endpoints declare it.
44
+ * out; another HTTP scheme's or Basic's 401 names that scheme, an API key's none, and nothing
45
+ * steps up under it. An error it declares is sent as its endpoints declare it.
46
46
  */
47
47
  readonly authentication?: D | undefined;
48
48
  /** The OAuth protected resource refusing: the one given to `layer`. */
@@ -63,9 +63,9 @@ type DeclaredOf<D> = D extends {
63
63
  * `authorization` presented a bearer token, or the `insufficient_scope` of a `Forbidden`
64
64
  * naming scopes. Given the protected resource `layer` was, every challenge names its metadata
65
65
  * URL and a 401's its `scopesRequired`. Under a descriptor of another scheme, it is the JSON
66
- * and status alone, a 401 naming that scheme. An error `authentication` declares is sent as
67
- * its endpoints declare it, its JSON with its status. `HttpServerResponse.toWeb` gives it as a
68
- * web `Response`.
66
+ * and status alone, a 401 naming that scheme, or none for an API key. An error
67
+ * `authentication` declares is sent as its endpoints declare it, its JSON with its status.
68
+ * `HttpServerResponse.toWeb` gives it as a web `Response`.
69
69
  */
70
70
  export declare const refusalResponse: <D extends Any = never>(error: Refusal | DeclaredOf<D>, options?: RefusalResponseOptions<D>) => HttpServerResponse.HttpServerResponse;
71
71
  /** What `make` takes besides the name and the identity. */
@@ -52,9 +52,9 @@ const withNoStoreAndChallenge = (response, challenge) => HttpServerResponse.setH
52
52
  * `authorization` presented a bearer token, or the `insufficient_scope` of a `Forbidden`
53
53
  * naming scopes. Given the protected resource `layer` was, every challenge names its metadata
54
54
  * URL and a 401's its `scopesRequired`. Under a descriptor of another scheme, it is the JSON
55
- * and status alone, a 401 naming that scheme. An error `authentication` declares is sent as
56
- * its endpoints declare it, its JSON with its status. `HttpServerResponse.toWeb` gives it as a
57
- * web `Response`.
55
+ * and status alone, a 401 naming that scheme, or none for an API key. An error
56
+ * `authentication` declares is sent as its endpoints declare it, its JSON with its status.
57
+ * `HttpServerResponse.toWeb` gives it as a web `Response`.
58
58
  */
59
59
  const refusalResponse = (error, options) => {
60
60
  const authentication = options?.authentication;
@@ -43,5 +43,5 @@ The tasks are in [Action.md](Action.md).
43
43
  - `Type 'CurrentUser' is not assignable to type 'never'` where a program calling an `Action.client` runs, or `Type 'CurrentUser' is missing the following properties from type 'Scope'` at `it.effect`: a call to a protected action reads the caller from its own context, never from the one the client was acquired in. Provide the caller around the call.
44
44
  - `Type 'Scope' is not assignable to type 'never'` where a program runs, or `Service not found: effect/Scope` in plain JavaScript: acquiring an `Action.client` builds, as a layer does. Acquire it in a builder or a layer, or run the program in `Effect.scoped`.
45
45
  - A builder runs on every request, or a route owes `HttpRouter.Request<"Requires", X>` for `X`, a service its builder yields: acquiring an `Action.client` runs the builders, and a handler acquires one on every request. Acquire the client in the builder, and call it in the handler.
46
- - An `Action.client` call dies with a `SchemaError`: the handler's success, or what it fails with, does not pass through its codec. A failure follows the `SchemaError` in the cause, as `Cause.pretty` shows. Return what the success schema accepts, and fail with an error the action declares.
46
+ - An `Action.client` call dies with a `SchemaError`: the handler's success, or what it fails with, does not pass through its codec. The cause holds the failure beside the `SchemaError`, as `Cause.pretty` shows: before it for a failure the action's errors reject, undeclared or breaking a check, after it for one they accept that does not encode. Return what the success schema accepts, and fail with an error the action declares.
47
47
  - `InvalidInput` with `Expected <Class>` from an `Action.client` call given a plain object: an input that is a class encodes only its instances. Pass `new Class({ ... })`.
@@ -70,7 +70,7 @@ export const builders = Action.layer([status, identity, issues, attachments, adm
70
70
 
71
71
  // kitchen-sink/src/server.ts
72
72
  Layer.mergeAll(
73
- HttpRouter.serve(publicRoutes).pipe(Layer.provide(listen(publicPort))),
73
+ HttpRouter.serve(Layer.merge(publicRoutes, socket)).pipe(Layer.provide(listen(publicPort))),
74
74
  HttpRouter.serve(adminRoutes).pipe(Layer.provide(listen(adminPort))),
75
75
  ).pipe(Layer.provide(builders), Layer.provide(memory));
76
76
  ```
package/docs/Action.md CHANGED
@@ -68,7 +68,7 @@ uses every option, sharing some by spreading a constant (`IssueWriteErrors`, `ch
68
68
  import it ([setup.md](setup.md#bundle-for-a-browser)).
69
69
  - **The name** matches `[A-Za-z0-9_-]{1,128}`, is not `then`, and is unique within each binding,
70
70
  MCP endpoint, Toolkit, CLI and client holding it.
71
- - **For no arguments, omit `input`.** A `Schema.Struct({})` accepts any value but `null`, and MCP
71
+ - **For no arguments, omit `input`.** A `Schema.Struct({})` accepts any value but `null` and `undefined`, and MCP
72
72
  refuses it as a tool's input ([ActionMcp.md](ActionMcp.md#describe-tools-to-a-model)).
73
73
  - **A field callers may omit is `Schema.optional`.** On the wire it also takes `null`, read as
74
74
  left out, as a tool's schema lists; a typed client refuses `null`. `Schema.optionalKey` takes
@@ -24,7 +24,7 @@ Search for a fragment of the message. The tasks are in [ActionMcp.md](ActionMcp.
24
24
  - A hand-written HTTP request answers 400 with JSON-RPC error `-32602`, `Required request metadata is missing` or `io.modelcontextprotocol/clientCapabilities request metadata is required`: it names 2026-07-28 in `MCP-Protocol-Version` and its `params._meta` lacks `io.modelcontextprotocol/protocolVersion`, for the first message, or `io.modelcontextprotocol/clientCapabilities`, for the second. Build it with `ActionMcp.request`, or copy the `curl` of [mcp-tools](../examples/mcp-tools/README.md#connect-a-client).
25
25
  - A hand-written HTTP request answers 400 with JSON-RPC error `-32020`, `MCP-Protocol-Version header is required`, `Mcp-Method header does not match request method` or `Mcp-Name header does not match request parameters`: those headers repeat a 2026-07-28 request's revision, method and `tools/call` name, and one is absent or differs from its body. Build it with `ActionMcp.request`.
26
26
  - A hand-written HTTP request answers an empty 406: its `Accept` header does not list both `application/json` and `text/event-stream`, as `*/*` does not. Send both.
27
- - A client asking for 2025-03-26 or 2024-11-05 is offered 2025-11-25, and disconnects if it cannot speak it: HTTP and stdio serve 2026-07-28, 2025-11-25 and 2025-06-18. Update the client.
27
+ - A client asking for 2025-03-26 or 2024-11-05 is offered 2025-11-25, and disconnects if it cannot speak it: HTTP and stdio serve 2026-07-28, 2025-11-25 and 2025-06-18, a `requestScoped` endpoint 2026-07-28 alone. Update the client.
28
28
  - A request written by hand to a stdio server answers JSON-RPC error `-32602`, `Invalid request metadata`: it is neither preceded by `initialize` nor carries the 2026-07-28 metadata. Open with `initialize` and `notifications/initialized`, or give the request's `_meta` its `io.modelcontextprotocol/protocolVersion` and `io.modelcontextprotocol/clientCapabilities`.
29
29
  - A client reports a broken transport from a stdio subprocess: something wrote to stdout. The global `console.log` did, or a layer provided around `runStdio` did, through the default logger, or through `Console` or a logger such as `Logger.consoleJson`, which `logToStderr` does not move. Remove the write, apply `ActionCli.logToStderr` last, or log JSON with `Logger.withConsoleError(Logger.formatJson)`.
30
30
  - A request carrying an `Origin` gets an empty 403: the origin is not in `allowedOrigins`. Add the exact origin, if the deployment trusts it.
package/docs/ActionMcp.md CHANGED
@@ -130,9 +130,9 @@ tool's read-only hint, and the contract's `mcp` option holds its `title`, its ot
130
130
  - MCP takes a write as destructive unless it states `destructiveHint: false`: one that only adds.
131
131
  - A tool's input is one object with keys. Omit `input` for a tool without arguments, and wrap a
132
132
  union, an array or a scalar in a field.
133
- - An argument the schema refuses, an undeclared one included, is answered by the native server
134
- before the handler runs, as an `isError` result whose text is `Invalid parameters for tool
135
- '<name>': …`, not `InvalidInput`. So constrain in the schema
133
+ - An argument the schema refuses, an undeclared one included, never reaches the handler: it
134
+ is an `isError` result, text `Invalid parameters for tool '<name>': …`, not `InvalidInput`,
135
+ and to 2025-06-18 a JSON-RPC error. So constrain in the schema
136
136
  what a model may send: an id written into an upstream URL is not made safe by
137
137
  `encodeURIComponent`, which leaves `..` alone.
138
138
  - A `Schema.makeFilter` check adds nothing to the tool's listed input schema, and
package/docs/README.md CHANGED
@@ -15,9 +15,10 @@ first (step 5), before the examples and the pages.
15
15
  limit, with no mark or with one that understates what is lost. If an output says it was
16
16
  truncated, read that page again alone.
17
17
  2. **Start from the example closest to what you are building** ([Examples](#examples)). Its
18
- README has a layout tree and a "Where to look" table naming the file for each thing. Copy its
19
- layout and idioms: the examples are the reference for how code is written. An example shows
20
- one way, not the rules, the alternatives or the traps: read steps 3 and 4 even when it fits.
18
+ README has a layout tree, and all but quickstart's a "Where to look" table naming the file
19
+ for each thing. Copy its layout and idioms: the examples are the reference for how code is
20
+ written. An example shows one way, not the rules, the alternatives or the traps: read steps
21
+ 3 and 4 even when it fits.
21
22
  3. **Read [Action.md](Action.md) completely.** Every surface builds on it.
22
23
  4. **Read the page of each surface you serve** ([Pages](#pages)), and the example files its task
23
24
  sections link.
@@ -22,9 +22,9 @@ One call, on each surface. An HTTP route is `POST <prefix>/<action>` with a JSON
22
22
  - **An action without input** takes `{}` and nothing else, on every surface. Over HTTP, send the body `{}` typed as JSON: no body is a **400**, and no `Content-Type` a **415**.
23
23
  - **A media field**, `Action.Image`, is `{ "data": "<base64>", "mimeType": "image/png" }` inside the JSON on every surface but MCP, which lifts it out of `structuredContent` into a block of its own: [Return images and other media](ActionMcp.md#return-images-and-other-media).
24
24
  - **A failure the action's errors reject**, undeclared or breaking a check, is its call's defect on every surface, beside the `SchemaError` saying why. A class error's checks are not rerun: one built with `disableChecks` is accepted, and fails to encode instead.
25
- - **Internal failures are never sent.** The cause of a defect goes to the log and, over HTTP, MCP and RPC, to the call's `ErrorReporter`s: those the server runs with, as provided around `HttpRouter.serve` or `Testing.layer`, win over those provided to one surface's layer, which only fill in what a request lacks.
25
+ - **Internal failures are never sent.** Over HTTP, MCP and RPC, the cause of a defect goes to the log and to the call's `ErrorReporter`s: those the server runs with, as provided around `HttpRouter.serve` or `Testing.layer`, win over those provided to one surface's layer, which only fill in what a request lacks.
26
26
  - **Messages for invalid input.** A message for input that does not decode names paths and what the schema expects, never a field's value. A path names every key it passes through, a record's keys and an undeclared key included, so never key a record by a secret such as an email or a token. A schema's own `message` annotation, or a filter's message, is sent as written, so never put the input in one.
27
- - **Earlier MCP revisions.** The MCP column is MCP 2026-07-28. A 2025-11-25 or 2025-06-18 client, over HTTP or stdio, gets `structuredContent` only for a success that is an object, and any other success as its text block alone, a string unquoted; a 2025-06-18 client gets invalid arguments as a JSON-RPC error instead of a result. Over HTTP such a client opens a session, which on an endpoint serving a protected tool only a signed-in caller does: it signs in for every request there, a public tool's call and `tools/list` included. Stdio authenticates nothing: the host provides the identity around `runStdio` ([Serve tools over stdio](ActionMcp.md#serve-tools-over-stdio)).
27
+ - **Earlier MCP revisions.** The MCP column is 2026-07-28. A 2025-11-25 or 2025-06-18 client, over HTTP or stdio, gets `structuredContent` only for a success that is an object, and any other success as its text block alone, a string unquoted; a 2025-06-18 client gets invalid arguments as a JSON-RPC error instead of a result. Over HTTP such a client opens a session, which on an endpoint serving a protected tool only a signed-in caller does: it signs in for every request there, a public tool's call and `tools/list` included. A `requestScoped` endpoint serves only 2026-07-28, and only `POST`. Stdio authenticates nothing: the host provides the identity around `runStdio` ([Serve tools over stdio](ActionMcp.md#serve-tools-over-stdio)).
28
28
  - **Request bodies have no size limit** unless the host sets one, on every route of the server, MCP endpoints included ([Serve the routes](ActionHttp.md#serve-the-routes)).
29
29
 
30
30
  [kitchen-sink/test/identity/identity.test.ts](../examples/kitchen-sink/test/identity/identity.test.ts) asserts the 401 and the 403 as sent, and [assistant/test/toolkit.test.ts](../examples/assistant/test/toolkit.test.ts) a refusal as a Toolkit result.
@@ -38,7 +38,7 @@ What the library does not do, where a reader might expect it to:
38
38
  - **Filter tool discovery by caller.** `tools/list` names every tool its endpoint serves, protected ones included, to anyone who may list them. Serve public tools on an endpoint of their own if signed-out callers must not see the protected ones.
39
39
  - **Limit requests.** A rate limit is the handler's, failing with an error its action declares, or middleware's.
40
40
  - **Allow browsers across origins.** CORS for JSON routes is the host's, with `HttpRouter.cors`; an MCP endpoint refuses a browser `Origin` it does not list ([Allow browser clients](ActionMcp.md#allow-browser-clients)).
41
- - **Stream, upload or retry.** Actions are unary JSON calls. One decoded input, one success or one declared error. Every HTTP route is a `POST`, a read-only action's included; RPC needs a protocol speaking JSON.
42
- - **Expire MCP sessions, or serve MCP features other than tools.** A session a client of a 2025 revision opens over HTTP lasts until that client ends it or the process stops, and a `requestScoped` endpoint opens none ([Serve tools over HTTP](ActionMcp.md#serve-tools-over-http)). Prompts and resources are Effect's native ones, given as `features` ([Add native prompts and resources](ActionMcp.md#add-native-prompts-and-resources)).
41
+ - **Stream, upload or retry.** Actions are unary JSON calls: one input, one success or one declared error. Every HTTP route is a `POST`, a read-only action's included; RPC needs a protocol speaking JSON.
42
+ - **Expire MCP sessions, or serve MCP features other than tools.** A session a client of a 2025 revision opens over HTTP lasts until that client ends it or the process stops ([Serve tools over HTTP](ActionMcp.md#serve-tools-over-http)). Prompts and resources are Effect's native ones, given as `features` ([Add native prompts and resources](ActionMcp.md#add-native-prompts-and-resources)).
43
43
  - **Mix identities.** An action names one identity service, and a remote surface one authentication descriptor.
44
44
  - **Harden a deployment.** Real token validation, request limits and error reporting are the application's. The examples mark each shortcut they take `DEMO ONLY`: [examples](../examples/README.md).
package/docs/setup.md CHANGED
@@ -13,12 +13,12 @@ When something fails, search [setup-failures.md](setup-failures.md). Reading ord
13
13
  pnpm add @gjermundgaraba/effect-actions effect@~4.0.4
14
14
  ```
15
15
 
16
- | Need | Add |
17
- | ----------------------------------- | ---------------------------------------------------------------- |
18
- | Node HTTP server, stdio host or CLI | `@effect/platform-node@~4.0.4` |
19
- | Tests | `vitest@^5.0.3` and `@effect/vitest@~4.0.4`, as dev dependencies |
20
- | Type checking | `typescript@^7.0.2`, as a dev dependency |
21
- | Running a TypeScript entrypoint | `tsx`, as a dev dependency: `node --import tsx <entrypoint>.ts` |
16
+ | Need | Add |
17
+ | ----------------------------------- | --------------------------------------------------------------- |
18
+ | Node HTTP server, stdio host or CLI | `@effect/platform-node@~4.0.4` |
19
+ | Tests | `vitest@^5` and `@effect/vitest@~4.0.4`, as dev dependencies |
20
+ | Type checking | `typescript@^7.0.2`, as a dev dependency |
21
+ | Running a TypeScript entrypoint | `tsx`, as a dev dependency: `node --import tsx <entrypoint>.ts` |
22
22
 
23
23
  The `effect` peer admits the 4.0.x patches from the oldest whose APIs the package uses, and no
24
24
  minor release: a minor release may change the unstable Effect modules the surfaces build on.
@@ -253,21 +253,21 @@ search for in the file.
253
253
 
254
254
  ### ActionToolkit
255
255
 
256
- | Export or option | File |
257
- | --------------------------------------------------- | ------------------------------------ |
258
- | `make`: `actions`, `needsApproval` (a boolean rule) | `src/issues/assistant.ts` |
259
- | `toolkit` given to `LanguageModel` | `src/issues/assistant.ts` (`triage`) |
260
- | `layer`, and the caller per turn | `src/agent.ts` |
261
- | `toolkit` and the model yielded in a builder | `src/assistant/handlers.ts` |
262
- | `layer` provided to the routes | `src/routes.ts` (`assistantTools`) |
263
- | An approval answered in a later request | `src/assistant/handlers.ts` |
264
- | `tools.handle`, a call made by hand | `test/issues/assistant.test.ts` |
256
+ | Export or option | File |
257
+ | --------------------------------------------------------- | ------------------------------------ |
258
+ | `make`: `actions`, `needsApproval` (a boolean rule) | `src/issues/assistant.ts` |
259
+ | `toolkit` given to `LanguageModel` | `src/issues/assistant.ts` (`triage`) |
260
+ | `layer`, and the caller per turn | `src/agent.ts` |
261
+ | `toolkit` and the model yielded in a builder | `src/assistant/handlers.ts` |
262
+ | `layer` provided to the routes | `src/routes.ts` (`assistantTools`) |
263
+ | An approval answered in a later request (`openApprovals`) | `src/assistant/handlers.ts` |
264
+ | `tools.handle`, a call made by hand | `test/issues/assistant.test.ts` |
265
265
 
266
266
  ### ActionCli
267
267
 
268
268
  | Export or option | File |
269
269
  | -------------------------------------------------------------- | ------------------------------------------ |
270
- | `remote`: `name`, `commands` | `src/cli.ts` |
270
+ | `remote`: `name`, `commands`, `client` | `src/cli.ts` |
271
271
  | `commands`: `stdin`, `positional`, `aliases`, `render`, `name` | `src/cli.ts` |
272
272
  | A client from `Config`, its credentials optional | `src/cli.ts` |
273
273
  | `make`, with a trusted identity the host supplies | `src/ops.ts` |
@@ -299,9 +299,9 @@ Left out because this application has no honest place for them:
299
299
  - `Action.implement` with a plain record of handlers: every implementation of several actions
300
300
  here has a builder. `implementation.actions`. `mcp._meta`.
301
301
  - `ActionCli.command` and `remoteCommand`, one action as one command; `make`'s and `remote`'s
302
- `actions`; `remote`'s static `client` option. Both CLIs here are aggregates of every action,
303
- and the remote one reads its client from `Config`. `subcommands` and `toUserError`, a command
304
- written by hand: [notes-service](../notes-service/) has one.
302
+ `actions`. Both CLIs here are aggregates of every action, and the remote one reads its client
303
+ from `Config`. `subcommands` and `toUserError`, a command written by hand:
304
+ [notes-service](../notes-service/) has two.
305
305
  - `ActionRpc.layer`'s `actions`, `Rpc.group`, and `ActionRpc.client`'s options.
306
306
  - A binding's other fields, `Http.actions`, `Http.error` and `Http.authentication`.
307
307
  - `ActionMcp`'s `path`, `description`, `websiteUrl`, `icons` and `extensions`; `fetchClient`'s
@@ -14,7 +14,8 @@ import { status } from "./workspaces/handlers.js";
14
14
  import { WorkspaceRegistry } from "./workspaces/registry.js";
15
15
 
16
16
  // Entrypoint: an MCP server a local agent starts as a subprocess, such as
17
- // `claude mcp add tracker -- node --import tsx examples/kitchen-sink/src/stdio.ts`.
17
+ // `claude mcp add tracker -- "$PWD/node_modules/.bin/tsx" "$PWD/examples/kitchen-sink/src/stdio.ts"`
18
+ // from the repository root: mcp-tools' README says why the paths are full.
18
19
  // It lists the implementations it serves itself, and imports nothing of the HTTP router. They
19
20
  // are those of the `/mcp` endpoint, with its tools and features and the same `authorize`.
20
21
  // stdio is a local surface: it takes no `authentication`, since no token arrives.
@@ -103,7 +103,7 @@ src/
103
103
  ├── server.ts entrypoint: the HTTP server
104
104
  ├── worker.ts entrypoint: a fetch handler for a serverless host
105
105
  ├── stdio.ts entrypoint: MCP for a local agent
106
- ├── commands.ts the commands calling the server, one written by hand, and their connection
106
+ ├── commands.ts the commands calling the server, two written by hand, and their connection
107
107
  ├── cli.ts entrypoint: the commands
108
108
  └── browser.ts client module: promises for a web page
109
109
  test/
@@ -10,7 +10,8 @@ import { NoteStore } from "./notes/store.js";
10
10
  import { status } from "./status/handlers.js";
11
11
 
12
12
  // Entrypoint: an MCP server a local agent starts as a subprocess, such as
13
- // `claude mcp add notes -- node --import tsx examples/notes-service/src/stdio.ts`.
13
+ // `claude mcp add notes -- "$PWD/node_modules/.bin/tsx" "$PWD/examples/notes-service/src/stdio.ts"`
14
+ // from the repository root: mcp-tools' README says why the paths are full.
14
15
  // The same implementations as the HTTP server, and the same `authorize`. No token arrives
15
16
  // over stdio, so this host names the caller itself. It is a process of its own with services
16
17
  // of its own: this in-memory store holds its notes, not the running server's. To share them,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjermundgaraba/effect-actions",
3
- "version": "0.18.1",
3
+ "version": "0.18.2",
4
4
  "description": "Define Effect action contracts once and project them onto HTTP, MCP, Effect RPC, native Toolkits, and CLIs.",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -56,9 +56,9 @@
56
56
  "effect": "4.0.5",
57
57
  "tsx": "4.23.15",
58
58
  "typescript": "7.0.2",
59
- "vite": "npm:@voidzero-dev/vite-plus-core@1.2.0",
60
- "vite-plus": "1.2.0",
61
- "vitest": "5.0.4"
59
+ "vite": "npm:@voidzero-dev/vite-plus-core@1.3.0",
60
+ "vite-plus": "1.3.0",
61
+ "vitest": "5.0.5"
62
62
  },
63
63
  "peerDependencies": {
64
64
  "effect": "~4.0.4"
@@ -66,7 +66,7 @@
66
66
  "devEngines": {
67
67
  "packageManager": {
68
68
  "name": "pnpm",
69
- "version": "12.5.1",
69
+ "version": "12.14.0",
70
70
  "onFail": "download"
71
71
  },
72
72
  "runtime": {