@feniix/bridgekit 0.9.4 → 0.9.5
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/CHANGELOG.md +18 -0
- package/README.md +94 -53
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,24 @@ All notable changes to `@feniix/bridgekit` are documented here. The format
|
|
|
4
4
|
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project
|
|
5
5
|
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.9.5] - Unreleased
|
|
8
|
+
|
|
9
|
+
### Documentation
|
|
10
|
+
|
|
11
|
+
- README restructured to quickstart-first ordering: a copy-pasteable
|
|
12
|
+
three-file working example (`tools.ts`, `mcp-server.ts`,
|
|
13
|
+
`pi-extension.ts`) now lands above the fold; runtime requirements,
|
|
14
|
+
the import map, best practices, packaging, and the coding-agent
|
|
15
|
+
section all move below. Content preserved; no new entrypoints, no
|
|
16
|
+
API changes, no behavioral effects. Resolves
|
|
17
|
+
[#19](https://github.com/feniix/bridgekit/issues/19).
|
|
18
|
+
- `docs/packaging-invariants.md` adds a cross-reference under
|
|
19
|
+
`inv-mcp-sdk-major` pointing at `toInputSchema`'s JSDoc in
|
|
20
|
+
`src/adapters/mcp.ts` as the canonical record of the SDK-v1
|
|
21
|
+
`inputSchema.type` Zod-validation quirk that the `allOf` →
|
|
22
|
+
`type: "object"` synthesis addresses. Resolves
|
|
23
|
+
[#45](https://github.com/feniix/bridgekit/issues/45).
|
|
24
|
+
|
|
7
25
|
## [0.9.4] - 2026-05-27
|
|
8
26
|
|
|
9
27
|
### Fixed
|
package/README.md
CHANGED
|
@@ -2,20 +2,74 @@
|
|
|
2
2
|
|
|
3
3
|
BridgeKit provides reusable TypeBox-backed tool definitions and adapters for exposing one tool implementation through pi, MCP, and other hosts.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Quickstart
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```ts
|
|
8
|
+
// src/tools.ts
|
|
9
|
+
import { Type } from "typebox";
|
|
10
|
+
import { definePortableTool } from "@feniix/bridgekit";
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
export const echoTool = definePortableTool({
|
|
13
|
+
name: "echo",
|
|
14
|
+
title: "Echo",
|
|
15
|
+
description: "Echo text back to the caller.",
|
|
16
|
+
parameters: Type.Object({ text: Type.String() }),
|
|
17
|
+
execute(args, ctx) {
|
|
18
|
+
return {
|
|
19
|
+
text: args.text,
|
|
20
|
+
structuredContent: { text: args.text, host: ctx.host },
|
|
21
|
+
};
|
|
22
|
+
},
|
|
23
|
+
hostExtras: {
|
|
24
|
+
pi: { pendingMessage: "Echoing..." },
|
|
25
|
+
mcp: { annotations: { readOnlyHint: true } },
|
|
26
|
+
},
|
|
27
|
+
});
|
|
10
28
|
|
|
11
|
-
|
|
29
|
+
export function createTools() {
|
|
30
|
+
return [echoTool];
|
|
31
|
+
}
|
|
32
|
+
```
|
|
12
33
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
34
|
+
```ts
|
|
35
|
+
// src/mcp-server.ts
|
|
36
|
+
import { runMcpStdioServer } from "@feniix/bridgekit/mcp";
|
|
37
|
+
import { createTools } from "./tools.js";
|
|
17
38
|
|
|
18
|
-
|
|
39
|
+
await runMcpStdioServer({
|
|
40
|
+
name: "my-tools",
|
|
41
|
+
version: "0.1.0",
|
|
42
|
+
tools: createTools(),
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
// src/pi-extension.ts
|
|
48
|
+
import { registerPiTools } from "@feniix/bridgekit/pi";
|
|
49
|
+
import { createTools } from "./tools.js";
|
|
50
|
+
|
|
51
|
+
export default function extension(pi: Parameters<typeof registerPiTools>[0]) {
|
|
52
|
+
registerPiTools(pi, createTools());
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Install
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm install @feniix/bridgekit typebox
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
This package is ESM-only and supports Node.js 22.19.0 or newer. Published modules are import-passive and marked as side-effect free; tools are registered or servers are started only when the exported adapter functions are called.
|
|
63
|
+
|
|
64
|
+
## Why
|
|
65
|
+
|
|
66
|
+
- Define a tool once; ship it to pi and MCP (and custom hosts) without per-host forks.
|
|
67
|
+
- Host-neutral tool files: no pi or MCP SDK imports in the tool definition itself.
|
|
68
|
+
- TypeBox schemas pass through to MCP `inputSchema` directly — no JSON Schema conversion step.
|
|
69
|
+
- Import-passive, `sideEffects: false`, three-entrypoint split (`.`, `./pi`, `./mcp`) so pi-only consumers do not pull the MCP SDK and vice versa.
|
|
70
|
+
- Conformance-tested public surface: a packed-install smoke test enforces the runtime export set, deep-import rejection, and type-level strictness against the installed declarations.
|
|
71
|
+
|
|
72
|
+
## API reference
|
|
19
73
|
|
|
20
74
|
```ts
|
|
21
75
|
import {
|
|
@@ -40,46 +94,7 @@ import { createMcpServer, runMcpStdioServer } from "@feniix/bridgekit/mcp";
|
|
|
40
94
|
|
|
41
95
|
Do not deep-import from `dist/` or `src/` in consuming packages.
|
|
42
96
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
Define tools once in host-neutral files:
|
|
46
|
-
|
|
47
|
-
```ts
|
|
48
|
-
import { Type } from "typebox";
|
|
49
|
-
import { definePortableTool } from "@feniix/bridgekit";
|
|
50
|
-
|
|
51
|
-
export const echoTool = definePortableTool({
|
|
52
|
-
name: "echo",
|
|
53
|
-
title: "Echo",
|
|
54
|
-
description: "Echo text.",
|
|
55
|
-
parameters: Type.Object({ text: Type.String() }),
|
|
56
|
-
execute(args, ctx) {
|
|
57
|
-
return {
|
|
58
|
-
text: args.text,
|
|
59
|
-
structuredContent: { text: args.text, host: ctx.host },
|
|
60
|
-
};
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
export function createTools() {
|
|
65
|
-
return [echoTool];
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
Tool definition best practices:
|
|
70
|
-
|
|
71
|
-
- Keep tool files host-neutral: no pi imports, no MCP SDK imports.
|
|
72
|
-
- Use TypeBox `Type.Object(...)` schemas so MCP can expose input schemas directly.
|
|
73
|
-
- Return `text` for model-visible output and `structuredContent` for machine-readable data.
|
|
74
|
-
- Use `isError: true` for expected/domain failures that should be represented as tool output.
|
|
75
|
-
- Throw only for unexpected programmer, adapter, or runtime failures.
|
|
76
|
-
- Respect `ctx.signal` in long-running tools.
|
|
77
|
-
- Use `ctx.progress?.(...)` for incremental updates.
|
|
78
|
-
- Keep modules import-passive; do not register tools or start servers at import time.
|
|
79
|
-
- For stateful tools, export a `createTools()` factory instead of a module-level singleton so each host runtime gets isolated state.
|
|
80
|
-
- TypeBox validation happens before `execute`; use a permissive schema plus domain validation if you need custom guidance for structurally invalid input.
|
|
81
|
-
|
|
82
|
-
## pi adapter
|
|
97
|
+
### pi adapter
|
|
83
98
|
|
|
84
99
|
```ts
|
|
85
100
|
import { registerPiTools } from "@feniix/bridgekit/pi";
|
|
@@ -141,7 +156,7 @@ new default `"return"` mode, prefer the result guards over inspecting a
|
|
|
141
156
|
`"domain"`). The guards operate on a `PortableToolResult`; they are not
|
|
142
157
|
designed to be called on the pi adapter's wire object.
|
|
143
158
|
|
|
144
|
-
|
|
159
|
+
#### Per-host metadata via `hostExtras`
|
|
145
160
|
|
|
146
161
|
`PortableTool.hostExtras` is an optional namespace for host-specific fields that should travel with the tool definition rather than a parallel sidecar map. The pi adapter reads `hostExtras.pi`; the MCP adapter reads `hostExtras.mcp`; each adapter ignores keys it does not recognise. Tools that omit `hostExtras` see no behavior change.
|
|
147
162
|
|
|
@@ -174,7 +189,7 @@ export const generateSummaryTool = definePortableTool({
|
|
|
174
189
|
|
|
175
190
|
See `docs/rfc-host-extras.md` for the design rationale (which fields are in scope, why a top-level field beats a sidecar map, the closure rule for future additions). `PortableToolHostExtras` is module-augmentable for custom host adapters; declare your namespace via `declare module "@feniix/bridgekit"`.
|
|
176
191
|
|
|
177
|
-
|
|
192
|
+
### MCP adapter
|
|
178
193
|
|
|
179
194
|
```ts
|
|
180
195
|
import { realpathSync } from "node:fs";
|
|
@@ -217,7 +232,7 @@ Portable validation failures and portable `isError: true` results return `CallTo
|
|
|
217
232
|
|
|
218
233
|
The two adapters now read in parallel: invalid args and portable `isError` results return `{ isError: true }` from both hosts by default, and the same result-guard helpers (`isValidationFailure`, `isDomainFailure`) narrow them on either side.
|
|
219
234
|
|
|
220
|
-
|
|
235
|
+
### Custom host typing
|
|
221
236
|
|
|
222
237
|
Default portable tools accept the built-in host union:
|
|
223
238
|
|
|
@@ -252,7 +267,24 @@ void hostValue;
|
|
|
252
267
|
|
|
253
268
|
Use `PortableToolHost<CustomHost>` for values that may be either a built-in host or your extension. Use the `PortableTool`/`PortableToolContext` generic when a tool or adapter is custom-host-only.
|
|
254
269
|
|
|
255
|
-
##
|
|
270
|
+
## Best practices
|
|
271
|
+
|
|
272
|
+
Tool definition best practices:
|
|
273
|
+
|
|
274
|
+
- Keep tool files host-neutral: no pi imports, no MCP SDK imports.
|
|
275
|
+
- Use TypeBox `Type.Object(...)` schemas so MCP can expose input schemas directly.
|
|
276
|
+
- Return `text` for model-visible output and `structuredContent` for machine-readable data.
|
|
277
|
+
- Use `isError: true` for expected/domain failures that should be represented as tool output.
|
|
278
|
+
- Throw only for unexpected programmer, adapter, or runtime failures.
|
|
279
|
+
- Respect `ctx.signal` in long-running tools.
|
|
280
|
+
- Use `ctx.progress?.(...)` for incremental updates.
|
|
281
|
+
- Keep modules import-passive; do not register tools or start servers at import time.
|
|
282
|
+
- For stateful tools, export a `createTools()` factory instead of a module-level singleton so each host runtime gets isolated state.
|
|
283
|
+
- TypeBox validation happens before `execute`; use a permissive schema plus domain validation if you need custom guidance for structurally invalid input.
|
|
284
|
+
|
|
285
|
+
## Packaging
|
|
286
|
+
|
|
287
|
+
Package and release checklist:
|
|
256
288
|
|
|
257
289
|
- Publish compiled JavaScript plus generated `.d.ts` declarations for runtime entrypoints.
|
|
258
290
|
- Keep `exports`, `main`, and `types` aligned with built files.
|
|
@@ -267,3 +299,12 @@ Use `PortableToolHost<CustomHost>` for values that may be either a built-in host
|
|
|
267
299
|
- Treat `docs/releasing.md` as the future release handoff; this repository is not configured for automated publish yet.
|
|
268
300
|
|
|
269
301
|
See `examples/README.md` for complete copyable examples.
|
|
302
|
+
|
|
303
|
+
## For coding agents
|
|
304
|
+
|
|
305
|
+
Read these files in order:
|
|
306
|
+
|
|
307
|
+
1. `README.md` — public API, contracts, and best practices.
|
|
308
|
+
2. `llms.txt` — compact agent-facing usage rules and anti-patterns.
|
|
309
|
+
3. `examples/README.md` — copyable layouts for shared tools, pi extensions, MCP stdio servers, and custom hosts.
|
|
310
|
+
4. Published declarations such as `dist/src/index.d.ts`, `dist/src/pi.d.ts`, and `dist/src/mcp.d.ts` — canonical installed-package type contracts. In a source checkout, the matching `src/` files contain the same implementation context.
|