toolcraft 0.0.7 → 0.0.9
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 +3 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +26 -9
- package/dist/mcp-proxy.d.ts +4 -1
- package/dist/mcp-proxy.js +4 -4
- package/dist/mcp.d.ts +1 -0
- package/dist/mcp.js +2 -2
- package/dist/sdk.d.ts +1 -0
- package/dist/sdk.js +1 -1
- package/node_modules/tiny-mcp-client/README.md +97 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -444,17 +444,20 @@ If you have an existing MCP server you want to keep running, use the MCP proxy:
|
|
|
444
444
|
- `presets?: boolean` — enables `--preset <path>` for loading parameter defaults from JSON files.
|
|
445
445
|
- `apiVersion?: string` — for `requires.apiVersion`.
|
|
446
446
|
- `humanInLoop?: HumanInLoopRuntimeOptions`
|
|
447
|
+
- `projectRoot?: string` — root used for MCP proxy cache files (`.toolcraft/mcp/*.json`).
|
|
447
448
|
|
|
448
449
|
### `createSDK(root, options)`
|
|
449
450
|
|
|
450
451
|
- `casing?: "camel"` — generated SDK member style.
|
|
451
452
|
- `services?` / `humanInLoop?` / `apiVersion?`
|
|
453
|
+
- `projectRoot?: string` — root used for MCP proxy cache files (`.toolcraft/mcp/*.json`).
|
|
452
454
|
|
|
453
455
|
### `createMCPServer(root, options)` / `runMCP(root, options)`
|
|
454
456
|
|
|
455
457
|
- `name: string`
|
|
456
458
|
- `version: string`
|
|
457
459
|
- `services?` / `humanInLoop?` / `apiVersion?`
|
|
460
|
+
- `projectRoot?: string` — root used for MCP proxy cache files (`.toolcraft/mcp/*.json`).
|
|
458
461
|
- `tools?: string[]` — allowlist of MCP tool names or group prefixes. Tool names are `__`-joined snake_case path segments (`root__bot__create`); a prefix like `root__bot` includes every descendant tool.
|
|
459
462
|
- `casing?: "snake" | "camel"` — affects MCP **input-schema property names** only. Tool names always stay `__`-joined snake_case.
|
|
460
463
|
|
package/dist/cli.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export interface RunCLIOptions<TServices extends object = Record<string, unknown
|
|
|
5
5
|
apiVersion?: string;
|
|
6
6
|
casing?: Casing;
|
|
7
7
|
humanInLoop?: HumanInLoopRuntimeOptions;
|
|
8
|
+
projectRoot?: string;
|
|
8
9
|
rootDisplayName?: string;
|
|
9
10
|
rootUsageName?: string;
|
|
10
11
|
services?: TServices;
|
package/dist/cli.js
CHANGED
|
@@ -714,20 +714,36 @@ function formatSecretDescription(secret) {
|
|
|
714
714
|
}
|
|
715
715
|
return secret.optional === true ? "Optional secret" : "Required secret";
|
|
716
716
|
}
|
|
717
|
-
function
|
|
718
|
-
|
|
717
|
+
function wrapOptionalCommandParameterToken(token, optional) {
|
|
718
|
+
return optional ? `[${token}]` : token;
|
|
719
|
+
}
|
|
720
|
+
function formatCommandDynamicParameterTokens(field, casing) {
|
|
721
|
+
const optional = field.optional || field.hasDefault;
|
|
722
|
+
return formatDynamicHelpFields(field, casing).map((row) => wrapOptionalCommandParameterToken(row.flags, optional));
|
|
723
|
+
}
|
|
724
|
+
function formatCommandParameterTokens(command, casing, globalLongOptionFlags) {
|
|
725
|
+
const collected = collectFields(command.params, casing, globalLongOptionFlags);
|
|
726
|
+
const fields = assignPositionals(collected.fields, command.positional);
|
|
727
|
+
return fields
|
|
728
|
+
.map((field) => wrapOptionalCommandParameterToken(formatHelpFieldFlags(field, globalLongOptionFlags), field.positionalIndex === undefined && (field.optional || field.hasDefault)))
|
|
729
|
+
.concat(collected.dynamicFields.flatMap((field) => formatCommandDynamicParameterTokens(field, casing)));
|
|
730
|
+
}
|
|
731
|
+
function formatCommandRowName(node, depth, casing, globalLongOptionFlags) {
|
|
732
|
+
const baseName = node.aliases.length === 0 ? node.name : `${node.name} (${node.aliases.join(", ")})`;
|
|
733
|
+
const parameterTokens = node.kind === "command" ? formatCommandParameterTokens(node, casing, globalLongOptionFlags) : [];
|
|
734
|
+
const name = parameterTokens.length === 0 ? baseName : `${baseName} ${parameterTokens.join(" ")}`;
|
|
719
735
|
return `${" ".repeat(depth)}${name}`;
|
|
720
736
|
}
|
|
721
|
-
function formatCommandRows(group, scope, depth = 0) {
|
|
737
|
+
function formatCommandRows(group, scope, casing, globalLongOptionFlags, depth = 0) {
|
|
722
738
|
return getVisibleChildren(group, scope).flatMap((child) => {
|
|
723
739
|
const row = {
|
|
724
|
-
name: formatCommandRowName(child, depth),
|
|
740
|
+
name: formatCommandRowName(child, depth, casing, globalLongOptionFlags),
|
|
725
741
|
description: child.description ?? "",
|
|
726
742
|
};
|
|
727
743
|
if (child.kind === "command") {
|
|
728
744
|
return [row];
|
|
729
745
|
}
|
|
730
|
-
return [row, ...formatCommandRows(child, scope, depth + 1)];
|
|
746
|
+
return [row, ...formatCommandRows(child, scope, casing, globalLongOptionFlags, depth + 1)];
|
|
731
747
|
});
|
|
732
748
|
}
|
|
733
749
|
function formatGlobalOptionRows(showVersion, presetsEnabled) {
|
|
@@ -766,9 +782,10 @@ function buildUsageLine(breadcrumb, rootUsageName, suffix) {
|
|
|
766
782
|
const subPath = breadcrumb.slice(1).join(" ");
|
|
767
783
|
return subPath ? `${rootUsageName} ${subPath} ${suffix}` : `${rootUsageName} ${suffix}`;
|
|
768
784
|
}
|
|
769
|
-
function renderGroupHelp(group, breadcrumb, scope, showVersion, presetsEnabled, rootUsageName) {
|
|
785
|
+
function renderGroupHelp(group, breadcrumb, scope, casing, showVersion, presetsEnabled, rootUsageName) {
|
|
770
786
|
const sections = [];
|
|
771
|
-
const
|
|
787
|
+
const globalLongOptionFlags = getGlobalLongOptionFlags(presetsEnabled);
|
|
788
|
+
const commandRows = formatCommandRows(group, scope, casing, globalLongOptionFlags);
|
|
772
789
|
if (commandRows.length > 0) {
|
|
773
790
|
sections.push(`${text.section("Commands:")}\n${formatCommandList(commandRows)}`);
|
|
774
791
|
}
|
|
@@ -833,7 +850,7 @@ async function renderGeneratedHelp(root, argv, options) {
|
|
|
833
850
|
const casing = options.casing ?? "kebab";
|
|
834
851
|
await withOutputFormat(output, async () => {
|
|
835
852
|
const rendered = target.node.kind === "group"
|
|
836
|
-
? renderGroupHelp(target.node, target.breadcrumb, "cli", options.version !== undefined, options.presets === true, options.rootUsageName)
|
|
853
|
+
? renderGroupHelp(target.node, target.breadcrumb, "cli", casing, options.version !== undefined, options.presets === true, options.rootUsageName)
|
|
837
854
|
: renderLeafHelp(target.node, target.breadcrumb, casing, options.presets === true, options.rootUsageName);
|
|
838
855
|
process.stdout.write(rendered);
|
|
839
856
|
});
|
|
@@ -2003,7 +2020,7 @@ function handleRunError(error, verbose) {
|
|
|
2003
2020
|
}
|
|
2004
2021
|
export async function runCLI(roots, options = {}) {
|
|
2005
2022
|
const root = mergeApprovalsGroup(normalizeRoots(roots, process.argv));
|
|
2006
|
-
await resolveMcpProxies(root);
|
|
2023
|
+
await resolveMcpProxies(root, { projectRoot: options.projectRoot });
|
|
2007
2024
|
const casing = options.casing ?? "kebab";
|
|
2008
2025
|
const services = (options.services ?? {});
|
|
2009
2026
|
const runtimeOptions = options.humanInLoop ?? {};
|
package/dist/mcp-proxy.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import type { McpServerConfig } from "@poe-code/agent-mcp-config";
|
|
2
2
|
import { McpClient } from "tiny-mcp-client";
|
|
3
3
|
import type { Group } from "./index.js";
|
|
4
|
+
export interface ResolveMcpProxyOptions {
|
|
5
|
+
projectRoot?: string;
|
|
6
|
+
}
|
|
4
7
|
export declare function hasMcpProxyGroups(root: Group<any>): boolean;
|
|
5
8
|
export declare function resolveCachePath(name: string, projectRoot?: string): string;
|
|
6
9
|
export declare function parseRefreshEnv(value: string | undefined): "all" | Set<string> | undefined;
|
|
7
10
|
export declare function dialUpstream(name: string, config: McpServerConfig): Promise<McpClient>;
|
|
8
|
-
export declare function resolveMcpProxies(root: Group<any
|
|
11
|
+
export declare function resolveMcpProxies(root: Group<any>, options?: ResolveMcpProxyOptions): Promise<void>;
|
package/dist/mcp-proxy.js
CHANGED
|
@@ -268,7 +268,7 @@ function isRefreshRequested(name, refresh) {
|
|
|
268
268
|
}
|
|
269
269
|
return refresh?.has(name) === true;
|
|
270
270
|
}
|
|
271
|
-
async function resolveSingleProxy(group) {
|
|
271
|
+
async function resolveSingleProxy(group, options) {
|
|
272
272
|
const internal = getInternalGroupConfig(group);
|
|
273
273
|
const config = internal.mcp;
|
|
274
274
|
if (config === undefined) {
|
|
@@ -276,7 +276,7 @@ async function resolveSingleProxy(group) {
|
|
|
276
276
|
}
|
|
277
277
|
const name = group.name;
|
|
278
278
|
try {
|
|
279
|
-
const cachePath = resolveCachePath(name);
|
|
279
|
+
const cachePath = resolveCachePath(name, options.projectRoot);
|
|
280
280
|
const refresh = parseRefreshEnv(process.env.TOOLCRAFT_MCP_REFRESH);
|
|
281
281
|
let cache;
|
|
282
282
|
if (isRefreshRequested(name, refresh)) {
|
|
@@ -377,7 +377,7 @@ export async function dialUpstream(name, config) {
|
|
|
377
377
|
await client.connect(transport);
|
|
378
378
|
return client;
|
|
379
379
|
}
|
|
380
|
-
export async function resolveMcpProxies(root) {
|
|
380
|
+
export async function resolveMcpProxies(root, options = {}) {
|
|
381
381
|
const groups = collectProxyGroups(root);
|
|
382
|
-
await Promise.all(groups.map((group) => resolveSingleProxy(group)));
|
|
382
|
+
await Promise.all(groups.map((group) => resolveSingleProxy(group, options)));
|
|
383
383
|
}
|
package/dist/mcp.d.ts
CHANGED
package/dist/mcp.js
CHANGED
|
@@ -419,7 +419,7 @@ function createDeferredMCPServer(root, options) {
|
|
|
419
419
|
let serverPromise;
|
|
420
420
|
const resolveServer = () => {
|
|
421
421
|
serverPromise ??= (async () => {
|
|
422
|
-
await resolveMcpProxies(root);
|
|
422
|
+
await resolveMcpProxies(root, { projectRoot: options.projectRoot });
|
|
423
423
|
return createResolvedMCPServer(root, options);
|
|
424
424
|
})();
|
|
425
425
|
return serverPromise;
|
|
@@ -449,7 +449,7 @@ export function createMCPServer(roots, options) {
|
|
|
449
449
|
}
|
|
450
450
|
export async function runMCP(roots, options) {
|
|
451
451
|
const root = mergeApprovalsGroup(normalizeRoots(roots));
|
|
452
|
-
await resolveMcpProxies(root);
|
|
452
|
+
await resolveMcpProxies(root, { projectRoot: options.projectRoot });
|
|
453
453
|
const server = createResolvedMCPServer(root, options);
|
|
454
454
|
await server.listen();
|
|
455
455
|
}
|
package/dist/sdk.d.ts
CHANGED
|
@@ -63,6 +63,7 @@ export interface CreateSDKOptions<TServices extends object = Record<string, unkn
|
|
|
63
63
|
services?: TServices;
|
|
64
64
|
casing?: "camel";
|
|
65
65
|
humanInLoop?: HumanInLoopRuntimeOptions;
|
|
66
|
+
projectRoot?: string;
|
|
66
67
|
}
|
|
67
68
|
export declare function createSDK<TRootInfo, TServices extends object = Record<string, unknown>>(root: Group<any> & {
|
|
68
69
|
readonly __agentKitGroupTypeInfo: TRootInfo;
|
package/dist/sdk.js
CHANGED
|
@@ -234,7 +234,7 @@ function createDeferredSDK(root, options) {
|
|
|
234
234
|
let sdkPromise;
|
|
235
235
|
const resolveSDK = () => {
|
|
236
236
|
sdkPromise ??= (async () => {
|
|
237
|
-
await resolveMcpProxies(root);
|
|
237
|
+
await resolveMcpProxies(root, { projectRoot: options.projectRoot });
|
|
238
238
|
return createResolvedSDK(root, options);
|
|
239
239
|
})();
|
|
240
240
|
return sdkPromise;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# tiny-mcp-client
|
|
2
|
+
|
|
3
|
+
`tiny-mcp-client` is a lightweight Model Context Protocol client used by tests, fixtures, and package integrations. It supports stdio transports, streamable HTTP transports, in-memory test pairs, JSON-RPC helpers, and OAuth metadata discovery for OAuth-protected MCP HTTP servers.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { HttpTransport, McpClient } from "tiny-mcp-client";
|
|
9
|
+
|
|
10
|
+
const client = new McpClient({
|
|
11
|
+
clientInfo: { name: "demo", version: "0.1.0" },
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
await client.connect(new HttpTransport({ url: "http://127.0.0.1:3000/mcp" }));
|
|
15
|
+
const tools = await client.listTools();
|
|
16
|
+
console.log(tools);
|
|
17
|
+
await client.close();
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Transports
|
|
21
|
+
|
|
22
|
+
| Transport | Description |
|
|
23
|
+
|-----------|-------------|
|
|
24
|
+
| `StdioTransport` | Spawns an MCP server process and communicates over stdio. |
|
|
25
|
+
| `HttpTransport` | Connects to streamable HTTP MCP endpoints, including session IDs, SSE GET streams, and session termination. |
|
|
26
|
+
| `createInMemoryTransportPair()` | Creates paired streams for in-process tests. |
|
|
27
|
+
|
|
28
|
+
## OAuth HTTP support
|
|
29
|
+
|
|
30
|
+
`HttpTransport` accepts `oauth` options from `mcp-oauth`. When a protected server returns a Bearer `WWW-Authenticate` challenge, the transport discovers protected-resource metadata, loads authorization-server metadata, lets the OAuth provider handle authorization, and retries the request when credentials are available.
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { HttpTransport, createDefaultOAuthClientProvider } from "tiny-mcp-client";
|
|
34
|
+
|
|
35
|
+
const transport = new HttpTransport({
|
|
36
|
+
url: "https://mcp.example.com/mcp",
|
|
37
|
+
oauth: {
|
|
38
|
+
provider: createDefaultOAuthClientProvider({
|
|
39
|
+
client: {
|
|
40
|
+
mode: "dynamic",
|
|
41
|
+
metadata: {
|
|
42
|
+
clientName: "tiny-client",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
browser: {
|
|
46
|
+
openBrowser: async (url) => {
|
|
47
|
+
console.log(`Open ${url}`);
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
}),
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
You can also call `discoverOAuthMetadata(resourceUrl, options)` directly, or instantiate `OAuthMetadataDiscovery` with a custom `fetch` implementation and shared cache.
|
|
56
|
+
|
|
57
|
+
## Testing helpers
|
|
58
|
+
|
|
59
|
+
- `createTestPair()` and `createSdkTestPair()` create paired client/server fixtures.
|
|
60
|
+
- `createInMemoryTransportPair()` is useful for fast unit tests without opening sockets or spawning processes.
|
|
61
|
+
- JSON-RPC error constants are exported for assertions: `ERROR_PARSE`, `ERROR_INVALID_REQUEST`, `ERROR_METHOD_NOT_FOUND`, `ERROR_INVALID_PARAMS`, and `ERROR_INTERNAL`.
|
|
62
|
+
|
|
63
|
+
## Config options
|
|
64
|
+
|
|
65
|
+
### `McpClientOptions`
|
|
66
|
+
|
|
67
|
+
| Option | Type | Description |
|
|
68
|
+
|--------|------|-------------|
|
|
69
|
+
| `clientInfo` | `{ name: string; version: string }` | Required client identity sent during initialize. |
|
|
70
|
+
| `capabilities` | `ClientCapabilities` | Optional MCP client capabilities. |
|
|
71
|
+
| `onToolsChanged`, `onResourcesChanged`, `onPromptsChanged` | callbacks | Optional notification handlers. |
|
|
72
|
+
| `onResourceUpdated`, `onLog`, `onProgress` | callbacks | Optional resource/log/progress handlers. |
|
|
73
|
+
| `onSamplingRequest`, `onRootsList` | callbacks | Optional server-to-client request handlers. |
|
|
74
|
+
|
|
75
|
+
### `HttpTransportOptions`
|
|
76
|
+
|
|
77
|
+
| Option | Type | Description |
|
|
78
|
+
|--------|------|-------------|
|
|
79
|
+
| `url` | `string` | MCP HTTP endpoint URL. |
|
|
80
|
+
| `headers` | `HeadersInit` | Static headers added to requests. |
|
|
81
|
+
| `fetch` | `(input, init?) => Promise<Response>` | Custom fetch implementation. |
|
|
82
|
+
| `oauth` | `OAuthClientProviderOptions` | Enables OAuth authorization handling. |
|
|
83
|
+
| `oauthDiscoveryCache` | `OAuthDiscoveryCache` | Optional shared metadata cache. |
|
|
84
|
+
|
|
85
|
+
### `StdioTransportOptions`
|
|
86
|
+
|
|
87
|
+
| Option | Type | Description |
|
|
88
|
+
|--------|------|-------------|
|
|
89
|
+
| `command` | `string` | Server executable. |
|
|
90
|
+
| `args` | `string[]` | Server args. |
|
|
91
|
+
| `cwd` | `string` | Server working directory. |
|
|
92
|
+
| `env` | `NodeJS.ProcessEnv` | Server environment. |
|
|
93
|
+
| `spawn` | `StdioSpawn` | Custom spawn function for tests. |
|
|
94
|
+
|
|
95
|
+
## Environment variables
|
|
96
|
+
|
|
97
|
+
This package does not expose public environment variables. Pass process environment explicitly through `StdioTransportOptions.env` when a spawned MCP server needs it.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toolcraft",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"commander": "^14.0.3",
|
|
46
46
|
"console-table-printer": "^2.15.0",
|
|
47
47
|
"tiny-stdio-mcp-server": "^0.1.0",
|
|
48
|
-
"toolcraft-schema": "^0.0.
|
|
48
|
+
"toolcraft-schema": "^0.0.9"
|
|
49
49
|
},
|
|
50
50
|
"files": [
|
|
51
51
|
"dist"
|