@fgv/ts-extras-mcp 5.1.0-47 → 5.1.0-49

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.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/package.json +19 -9
  3. package/.rush/temp/1ef6da5e025cb1b91fb9dacea403fcf68d03a476.tar.log +0 -90
  4. package/.rush/temp/chunked-rush-logs/ts-extras-mcp.build.chunks.jsonl +0 -9
  5. package/.rush/temp/operation/build/all.log +0 -9
  6. package/.rush/temp/operation/build/log-chunks.jsonl +0 -9
  7. package/.rush/temp/operation/build/state.json +0 -3
  8. package/.rush/temp/shrinkwrap-deps.json +0 -735
  9. package/config/api-extractor.json +0 -38
  10. package/config/jest.config.json +0 -13
  11. package/config/rig.json +0 -6
  12. package/dist/test/unit/endToEnd.test.js +0 -220
  13. package/dist/test/unit/endToEnd.test.js.map +0 -1
  14. package/dist/test/unit/index.test.js +0 -41
  15. package/dist/test/unit/index.test.js.map +0 -1
  16. package/dist/test/unit/mcp.test.js +0 -494
  17. package/dist/test/unit/mcp.test.js.map +0 -1
  18. package/dist/test/unit/sdk.test.js +0 -68
  19. package/dist/test/unit/sdk.test.js.map +0 -1
  20. package/eslint.config.js +0 -15
  21. package/etc/ts-extras-mcp.api.md +0 -114
  22. package/lib/test/unit/endToEnd.test.d.ts +0 -13
  23. package/lib/test/unit/endToEnd.test.d.ts.map +0 -1
  24. package/lib/test/unit/endToEnd.test.js +0 -222
  25. package/lib/test/unit/endToEnd.test.js.map +0 -1
  26. package/lib/test/unit/index.test.d.ts +0 -2
  27. package/lib/test/unit/index.test.d.ts.map +0 -1
  28. package/lib/test/unit/index.test.js +0 -76
  29. package/lib/test/unit/index.test.js.map +0 -1
  30. package/lib/test/unit/mcp.test.d.ts +0 -2
  31. package/lib/test/unit/mcp.test.d.ts.map +0 -1
  32. package/lib/test/unit/mcp.test.js +0 -529
  33. package/lib/test/unit/mcp.test.js.map +0 -1
  34. package/lib/test/unit/sdk.test.d.ts +0 -2
  35. package/lib/test/unit/sdk.test.d.ts.map +0 -1
  36. package/lib/test/unit/sdk.test.js +0 -70
  37. package/lib/test/unit/sdk.test.js.map +0 -1
  38. package/rush-logs/ts-extras-mcp.build.cache.log +0 -3
  39. package/rush-logs/ts-extras-mcp.build.log +0 -9
  40. package/src/index.ts +0 -50
  41. package/src/packlets/mcp/adapter.ts +0 -155
  42. package/src/packlets/mcp/index.ts +0 -34
  43. package/src/packlets/mcp/model.ts +0 -235
  44. package/src/packlets/mcp/operations.ts +0 -181
  45. package/src/packlets/mcp/sdk.ts +0 -154
  46. package/src/packlets/mcp/session.ts +0 -137
  47. package/src/packlets/mcp/transports.ts +0 -111
  48. package/src/test/unit/endToEnd.test.ts +0 -254
  49. package/src/test/unit/index.test.ts +0 -43
  50. package/src/test/unit/mcp.test.ts +0 -601
  51. package/src/test/unit/sdk.test.ts +0 -73
  52. package/temp/build/lint/_eslint-5eVG3S6w.json +0 -54
  53. package/temp/build/typescript/ts_8nwakTlr.json +0 -1
  54. package/temp/ts-extras-mcp.api.json +0 -1843
  55. package/temp/ts-extras-mcp.api.md +0 -114
  56. package/tsconfig.json +0 -12
@@ -1 +0,0 @@
1
- {"version":3,"file":"sdk.test.d.ts","sourceRoot":"","sources":["../../../src/test/unit/sdk.test.ts"],"names":[],"mappings":""}
@@ -1,70 +0,0 @@
1
- "use strict";
2
- /*
3
- * Copyright (c) 2026 Erik Fortune
4
- *
5
- * Permission is hereby granted, free of charge, to any person obtaining a copy
6
- * of this software and associated documentation files (the "Software"), to deal
7
- * in the Software without restriction, including without limitation the rights
8
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- * copies of the Software, and to permit persons to whom the Software is
10
- * furnished to do so, subject to the following conditions:
11
- *
12
- * The above copyright notice and this permission notice shall be included in all
13
- * copies or substantial portions of the Software.
14
- *
15
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- * SOFTWARE.
22
- */
23
- Object.defineProperty(exports, "__esModule", { value: true });
24
- // Exercises the real SDK-isolation seam (the one file that imports @modelcontextprotocol/sdk).
25
- // Constructing the SDK objects is side-effect-free — no process is spawned and no network call is
26
- // made until a transport is connected, so these factory calls are safe in a unit test.
27
- // eslint-disable-next-line @rushstack/packlets/mechanics
28
- const sdk_1 = require("../../packlets/mcp/sdk");
29
- describe('sdk isolation seam', () => {
30
- describe('makeClient', () => {
31
- test('constructs a client exposing the projected surface', () => {
32
- const client = (0, sdk_1.makeClient)('test-client', '9.9.9');
33
- expect(typeof client.connect).toBe('function');
34
- expect(typeof client.listTools).toBe('function');
35
- expect(typeof client.callTool).toBe('function');
36
- expect(typeof client.close).toBe('function');
37
- expect(typeof client.getServerVersion).toBe('function');
38
- // Before connecting, the server identity is unknown.
39
- expect(client.getServerVersion()).toBeUndefined();
40
- });
41
- });
42
- describe('makeStdioTransport', () => {
43
- test('constructs a transport with full params (args/env/cwd)', () => {
44
- const transport = (0, sdk_1.makeStdioTransport)({
45
- command: 'node',
46
- args: ['--version'],
47
- env: { FOO: 'bar' },
48
- cwd: '/tmp'
49
- });
50
- expect(transport).toBeDefined();
51
- });
52
- test('constructs a transport with only a command (args omitted)', () => {
53
- const transport = (0, sdk_1.makeStdioTransport)({ command: 'node' });
54
- expect(transport).toBeDefined();
55
- });
56
- });
57
- describe('makeHttpTransport', () => {
58
- test('constructs a transport with headers', () => {
59
- const transport = (0, sdk_1.makeHttpTransport)(new URL('http://localhost:9000/mcp'), {
60
- authorization: 'Bearer x'
61
- });
62
- expect(transport).toBeDefined();
63
- });
64
- test('constructs a transport without headers', () => {
65
- const transport = (0, sdk_1.makeHttpTransport)(new URL('https://example.com/mcp'));
66
- expect(transport).toBeDefined();
67
- });
68
- });
69
- });
70
- //# sourceMappingURL=sdk.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sdk.test.js","sourceRoot":"","sources":["../../../src/test/unit/sdk.test.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;AAEH,+FAA+F;AAC/F,kGAAkG;AAClG,uFAAuF;AACvF,yDAAyD;AACzD,gDAA2F;AAE3F,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;QAC1B,IAAI,CAAC,oDAAoD,EAAE,GAAG,EAAE;YAC9D,MAAM,MAAM,GAAG,IAAA,gBAAU,EAAC,aAAa,EAAE,OAAO,CAAC,CAAC;YAClD,MAAM,CAAC,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC/C,MAAM,CAAC,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACjD,MAAM,CAAC,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAChD,MAAM,CAAC,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC7C,MAAM,CAAC,OAAO,MAAM,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACxD,qDAAqD;YACrD,MAAM,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC,aAAa,EAAE,CAAC;QACpD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAClC,IAAI,CAAC,wDAAwD,EAAE,GAAG,EAAE;YAClE,MAAM,SAAS,GAAG,IAAA,wBAAkB,EAAC;gBACnC,OAAO,EAAE,MAAM;gBACf,IAAI,EAAE,CAAC,WAAW,CAAC;gBACnB,GAAG,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE;gBACnB,GAAG,EAAE,MAAM;aACZ,CAAC,CAAC;YACH,MAAM,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,2DAA2D,EAAE,GAAG,EAAE;YACrE,MAAM,SAAS,GAAG,IAAA,wBAAkB,EAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;YAC1D,MAAM,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QAClC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;QACjC,IAAI,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC/C,MAAM,SAAS,GAAG,IAAA,uBAAiB,EAAC,IAAI,GAAG,CAAC,2BAA2B,CAAC,EAAE;gBACxE,aAAa,EAAE,UAAU;aAC1B,CAAC,CAAC;YACH,MAAM,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,wCAAwC,EAAE,GAAG,EAAE;YAClD,MAAM,SAAS,GAAG,IAAA,uBAAiB,EAAC,IAAI,GAAG,CAAC,yBAAyB,CAAC,CAAC,CAAC;YACxE,MAAM,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QAClC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n// Exercises the real SDK-isolation seam (the one file that imports @modelcontextprotocol/sdk).\n// Constructing the SDK objects is side-effect-free — no process is spawned and no network call is\n// made until a transport is connected, so these factory calls are safe in a unit test.\n// eslint-disable-next-line @rushstack/packlets/mechanics\nimport { makeClient, makeHttpTransport, makeStdioTransport } from '../../packlets/mcp/sdk';\n\ndescribe('sdk isolation seam', () => {\n describe('makeClient', () => {\n test('constructs a client exposing the projected surface', () => {\n const client = makeClient('test-client', '9.9.9');\n expect(typeof client.connect).toBe('function');\n expect(typeof client.listTools).toBe('function');\n expect(typeof client.callTool).toBe('function');\n expect(typeof client.close).toBe('function');\n expect(typeof client.getServerVersion).toBe('function');\n // Before connecting, the server identity is unknown.\n expect(client.getServerVersion()).toBeUndefined();\n });\n });\n\n describe('makeStdioTransport', () => {\n test('constructs a transport with full params (args/env/cwd)', () => {\n const transport = makeStdioTransport({\n command: 'node',\n args: ['--version'],\n env: { FOO: 'bar' },\n cwd: '/tmp'\n });\n expect(transport).toBeDefined();\n });\n\n test('constructs a transport with only a command (args omitted)', () => {\n const transport = makeStdioTransport({ command: 'node' });\n expect(transport).toBeDefined();\n });\n });\n\n describe('makeHttpTransport', () => {\n test('constructs a transport with headers', () => {\n const transport = makeHttpTransport(new URL('http://localhost:9000/mcp'), {\n authorization: 'Bearer x'\n });\n expect(transport).toBeDefined();\n });\n\n test('constructs a transport without headers', () => {\n const transport = makeHttpTransport(new URL('https://example.com/mcp'));\n expect(transport).toBeDefined();\n });\n });\n});\n"]}
@@ -1,3 +0,0 @@
1
- Caching build output folders: dist, lib, temp, .rush/temp/operation/build
2
- Successfully set cache entry.
3
- Cache key: 1ef6da5e025cb1b91fb9dacea403fcf68d03a476
@@ -1,9 +0,0 @@
1
- Invoking: heft build --clean
2
- ---- build started ----
3
- [build:typescript] The TypeScript compiler version 5.9.3 is newer than the latest version that was tested with Heft (5.8); it may not work correctly.
4
- [build:typescript] Using TypeScript version 5.9.3
5
- [build:lint] Using ESLint version 9.39.5
6
- [build:api-extractor] Using API Extractor version 7.58.9
7
- [build:api-extractor] Analysis will use the bundled TypeScript version 5.9.3
8
- ---- build finished (8.943s) ----
9
- -------------------- Finished (8.957s) --------------------
package/src/index.ts DELETED
@@ -1,50 +0,0 @@
1
- /*
2
- * Copyright (c) 2026 Erik Fortune
3
- *
4
- * Permission is hereby granted, free of charge, to any person obtaining a copy
5
- * of this software and associated documentation files (the "Software"), to deal
6
- * in the Software without restriction, including without limitation the rights
7
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
- * copies of the Software, and to permit persons to whom the Software is
9
- * furnished to do so, subject to the following conditions:
10
- *
11
- * The above copyright notice and this permission notice shall be included in all
12
- * copies or substantial portions of the Software.
13
- *
14
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
- * SOFTWARE.
21
- */
22
-
23
- /**
24
- * `@fgv/ts-extras-mcp` — a Result-integration boundary over `@modelcontextprotocol/sdk` that
25
- * connects to MCP (Model Context Protocol) servers, discovers their tools, and adapts each into
26
- * an `AiAssist.IAiClientTool` so it drops directly into `AiAssist.executeClientToolTurn` —
27
- * making any MCP server's tools callable across all four cloud providers with no per-provider work.
28
- *
29
- * Mirrors the discipline of `@fgv/ts-extras-webauthn` / `@fgv/ts-extras-transformers`: thin
30
- * `Result<T>` conversion over a well-maintained upstream SDK, with no opinionated orchestration
31
- * above the boundary.
32
- *
33
- * **In scope (slice 1, Node):** transport factories (`createStdioTransport`,
34
- * `createHttpTransport`), session lifecycle (`connectMcpSession`, `closeMcpSession`), tool
35
- * discovery + invocation (`listMcpTools`, `callMcpTool`), and the headline adapter
36
- * (`adaptMcpTools`) which gracefully degrades on tools whose `inputSchema` is outside the
37
- * supported JSON Schema subset (surfacing them on `skipped` and warning NOISILY).
38
- *
39
- * **Explicitly NOT in scope (deferred — see README / docs/FUTURE.md):**
40
- * - Browser sibling `@fgv/ts-web-extras-mcp`
41
- * - MCP resources / prompts / sampling features
42
- * - OAuth / managed auth (static headers only at v0.1)
43
- * - Multimodal tool-result passthrough (text-block projection only)
44
- * - Cross-server tool-name namespacing (duplicate names already fail loudly in
45
- * `executeClientToolTurn`)
46
- *
47
- * @packageDocumentation
48
- */
49
-
50
- export * from './packlets/mcp';
@@ -1,155 +0,0 @@
1
- /*
2
- * Copyright (c) 2026 Erik Fortune
3
- *
4
- * Permission is hereby granted, free of charge, to any person obtaining a copy
5
- * of this software and associated documentation files (the "Software"), to deal
6
- * in the Software without restriction, including without limitation the rights
7
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
- * copies of the Software, and to permit persons to whom the Software is
9
- * furnished to do so, subject to the following conditions:
10
- *
11
- * The above copyright notice and this permission notice shall be included in all
12
- * copies or substantial portions of the Software.
13
- *
14
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
- * SOFTWARE.
21
- */
22
-
23
- /**
24
- * The headline adapter — discovers an MCP server's tools and adapts each into an
25
- * `AiAssist.IAiClientTool`, gracefully degrading (Constraint 1) on any tool whose `inputSchema`
26
- * is outside the JSON Schema subset that `JsonSchema.fromJson` supports.
27
- * @packageDocumentation
28
- */
29
-
30
- import { type Result, succeed } from '@fgv/ts-utils';
31
- import { AiAssist } from '@fgv/ts-extras';
32
- import { Converters, JsonSchema, type JsonValue } from '@fgv/ts-json-base';
33
-
34
- import {
35
- type IAdaptMcpToolsOptions,
36
- type IAdaptMcpToolsResult,
37
- type IMcpSession,
38
- type IMcpSkippedTool,
39
- type IMcpToolDescriptor
40
- } from './model';
41
- import { callMcpTool, listMcpTools } from './operations';
42
-
43
- /**
44
- * Per-tool adaptation outcome: either an adapted client tool, or a structurally-surfaced skip.
45
- * `adaptMcpTools` never short-circuits on a skip — degradation is structural, not a failure.
46
- */
47
- type IAdaptOutcome =
48
- | { readonly kind: 'tool'; readonly tool: AiAssist.IAiClientTool }
49
- | { readonly kind: 'skipped'; readonly skipped: IMcpSkippedTool };
50
-
51
- /**
52
- * Builds the `execute` callback for an adapted MCP tool. Args arrive already validated against
53
- * the tool's `parametersSchema` by `executeClientToolTurn`; here we narrow to a `JsonObject`
54
- * (MCP arguments are always an object) and forward to {@link callMcpTool}, returning the
55
- * projected text content. A tool error surfaces as a `Failure` (never swallowed).
56
- */
57
- function _makeExecute(session: IMcpSession, name: string): (args: unknown) => Promise<Result<unknown>> {
58
- return async (args: unknown): Promise<Result<unknown>> => {
59
- const objResult = Converters.jsonObject
60
- .convert(args)
61
- .withErrorFormat((msg) => `tool '${name}': arguments must be a JSON object: ${msg}`);
62
- if (objResult.isFailure()) {
63
- return objResult;
64
- }
65
- return (await callMcpTool(session, name, objResult.value)).onSuccess((called) => succeed(called.content));
66
- };
67
- }
68
-
69
- /**
70
- * Adapts a single discovered tool. Returns a `skipped` outcome (never a failure) when the
71
- * tool's `inputSchema` is not a JSON object or is outside the `JsonSchema.fromJson` subset.
72
- */
73
- function _adaptOne(session: IMcpSession, descriptor: IMcpToolDescriptor): IAdaptOutcome {
74
- const { name, description, inputSchema, annotations } = descriptor;
75
-
76
- const skip = (reason: string, schema: JsonValue): IAdaptOutcome => ({
77
- kind: 'skipped',
78
- skipped: { name, reason, schema }
79
- });
80
-
81
- const asObject = Converters.jsonObject.convert(inputSchema);
82
- if (asObject.isFailure()) {
83
- return skip(`inputSchema is not a JSON object (${asObject.message})`, inputSchema);
84
- }
85
-
86
- const schemaResult = JsonSchema.fromJson(asObject.value);
87
- if (schemaResult.isFailure()) {
88
- return skip(schemaResult.message, inputSchema);
89
- }
90
-
91
- const config: AiAssist.IAiClientToolConfig = {
92
- type: 'client_tool',
93
- name,
94
- description: description ?? name,
95
- parametersSchema: schemaResult.value,
96
- // IMcpToolAnnotations maps 1:1 onto AiAssist.IAiToolAnnotations. Only set the field when the
97
- // server provided usable annotations, so a tool without them stays exactly as before.
98
- ...(annotations !== undefined ? { annotations } : {})
99
- };
100
- return {
101
- kind: 'tool',
102
- tool: { config, execute: _makeExecute(session, name) }
103
- };
104
- }
105
-
106
- /**
107
- * Discovers an MCP server's tools and adapts each into an `AiAssist.IAiClientTool` that drops
108
- * directly into `AiAssist.executeClientToolTurn`.
109
- *
110
- * @remarks
111
- * **Constraint 1 — graceful degradation with NOISY warnings.** A tool whose `inputSchema` is
112
- * outside the JSON Schema subset supported by `JsonSchema.fromJson` is NOT adapted (the model
113
- * must never be offered a tool whose args we can't validate). Instead it is:
114
- * 1. excluded from {@link IAdaptMcpToolsResult.tools};
115
- * 2. surfaced structurally on {@link IAdaptMcpToolsResult.skipped} with the tool name, the
116
- * JSON-pointer reason, and the raw failing schema; and
117
- * 3. logged as a NOISY `warning` (name + reason + raw schema) when an `options.logger` is
118
- * supplied — so pointing this at a new server immediately reveals every subset feature to
119
- * extend, with the schema in hand.
120
- *
121
- * The whole catalog never fails on a single bad schema; the only failure mode is an upstream
122
- * `listMcpTools` error.
123
- *
124
- * @param session - A connected session from `connectMcpSession`.
125
- * @param options - Optional logger for the NOISY skip warnings.
126
- * @returns `Success` with `{ tools, skipped }`, or `Failure` only if tool discovery fails.
127
- * @public
128
- */
129
- export async function adaptMcpTools(
130
- session: IMcpSession,
131
- options?: IAdaptMcpToolsOptions
132
- ): Promise<Result<IAdaptMcpToolsResult>> {
133
- return (await listMcpTools(session))
134
- .onSuccess((descriptors) => {
135
- const tools: AiAssist.IAiClientTool[] = [];
136
- const skipped: IMcpSkippedTool[] = [];
137
-
138
- for (const descriptor of descriptors) {
139
- const outcome = _adaptOne(session, descriptor);
140
- if (outcome.kind === 'tool') {
141
- tools.push(outcome.tool);
142
- } else {
143
- skipped.push(outcome.skipped);
144
- options?.logger?.warn(
145
- `mcp: skipping tool '${outcome.skipped.name}': inputSchema is outside the supported ` +
146
- `JSON Schema subset: ${outcome.skipped.reason}. ` +
147
- `Raw schema: ${JSON.stringify(outcome.skipped.schema)}`
148
- );
149
- }
150
- }
151
-
152
- return succeed<IAdaptMcpToolsResult>({ tools, skipped });
153
- })
154
- .withErrorFormat((msg) => `adaptMcpTools: ${msg}`);
155
- }
@@ -1,34 +0,0 @@
1
- /*
2
- * Copyright (c) 2026 Erik Fortune
3
- *
4
- * Permission is hereby granted, free of charge, to any person obtaining a copy
5
- * of this software and associated documentation files (the "Software"), to deal
6
- * in the Software without restriction, including without limitation the rights
7
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
- * copies of the Software, and to permit persons to whom the Software is
9
- * furnished to do so, subject to the following conditions:
10
- *
11
- * The above copyright notice and this permission notice shall be included in all
12
- * copies or substantial portions of the Software.
13
- *
14
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
- * SOFTWARE.
21
- */
22
-
23
- /**
24
- * Public surface of the MCP packlet.
25
- * @packageDocumentation
26
- */
27
-
28
- // `export *` (rather than named type-only re-exports) emits a runtime re-export of the
29
- // types-only module so it participates in coverage as a loaded (zero-statement) module.
30
- export * from './model';
31
- export { createHttpTransport, createStdioTransport } from './transports';
32
- export { closeMcpSession, connectMcpSession } from './session';
33
- export { callMcpTool, listMcpTools } from './operations';
34
- export { adaptMcpTools } from './adapter';
@@ -1,235 +0,0 @@
1
- /*
2
- * Copyright (c) 2026 Erik Fortune
3
- *
4
- * Permission is hereby granted, free of charge, to any person obtaining a copy
5
- * of this software and associated documentation files (the "Software"), to deal
6
- * in the Software without restriction, including without limitation the rights
7
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
- * copies of the Software, and to permit persons to whom the Software is
9
- * furnished to do so, subject to the following conditions:
10
- *
11
- * The above copyright notice and this permission notice shall be included in all
12
- * copies or substantial portions of the Software.
13
- *
14
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
- * SOFTWARE.
21
- */
22
-
23
- /**
24
- * Public types for the MCP → ai-assist client-tools boundary.
25
- * @packageDocumentation
26
- */
27
-
28
- import { type Logging } from '@fgv/ts-utils';
29
- import { type AiAssist } from '@fgv/ts-extras';
30
- import { type JsonValue } from '@fgv/ts-json-base';
31
-
32
- // ============================================================================
33
- // Transport
34
- // ============================================================================
35
-
36
- /**
37
- * Parameters for {@link createStdioTransport}. The transport spawns `command` as a
38
- * subprocess and speaks MCP over its stdin/stdout.
39
- *
40
- * @remarks
41
- * **Security:** stdio transport executes a consumer-supplied command. Treat `command`/`args`
42
- * as a trust boundary — never source them from untrusted input. See the package README.
43
- *
44
- * @public
45
- */
46
- export interface IMcpStdioTransportParams {
47
- /** Executable to spawn (e.g. `'npx'`, `'node'`, an absolute path). */
48
- readonly command: string;
49
- /** Arguments passed to the command. */
50
- readonly args?: ReadonlyArray<string>;
51
- /** Environment variables for the spawned process. When omitted, the SDK's safe default set is used. */
52
- readonly env?: Record<string, string>;
53
- /** Working directory for the spawned process. */
54
- readonly cwd?: string;
55
- }
56
-
57
- /**
58
- * Parameters for {@link createHttpTransport}. The transport connects to a Streamable-HTTP MCP
59
- * endpoint.
60
- * @public
61
- */
62
- export interface IMcpHttpTransportParams {
63
- /** Absolute `http`/`https` URL of the MCP server endpoint. */
64
- readonly url: string;
65
- /** Optional static headers (e.g. an `Authorization` bearer token). OAuth/managed auth is out of scope at v0.1. */
66
- readonly headers?: Record<string, string>;
67
- }
68
-
69
- /**
70
- * Opaque handle to an MCP transport produced by {@link createStdioTransport} or
71
- * {@link createHttpTransport}. Hand it to {@link connectMcpSession}; do not construct directly.
72
- * @public
73
- */
74
- export interface IMcpTransport {
75
- /** Which transport kind this handle wraps. */
76
- readonly transportKind: 'stdio' | 'http';
77
- }
78
-
79
- // ============================================================================
80
- // Session
81
- // ============================================================================
82
-
83
- /**
84
- * Parameters for {@link connectMcpSession}.
85
- * @public
86
- */
87
- export interface IConnectMcpSessionParams {
88
- /** A transport produced by {@link createStdioTransport} / {@link createHttpTransport}. */
89
- readonly transport: IMcpTransport;
90
- /** Client name advertised to the server during the initialize handshake. Default `'@fgv/ts-extras-mcp'`. */
91
- readonly clientName?: string;
92
- /** Client version advertised to the server. Default the package version. */
93
- readonly clientVersion?: string;
94
- /** Optional logger for connection diagnostics. */
95
- readonly logger?: Logging.ILogger;
96
- }
97
-
98
- /**
99
- * Server identity reported during the MCP initialize handshake.
100
- * @public
101
- */
102
- export interface IMcpServerInfo {
103
- /** Server-advertised name. */
104
- readonly name: string;
105
- /** Server-advertised version. */
106
- readonly version: string;
107
- }
108
-
109
- /**
110
- * Opaque handle to a connected MCP session. Pass it to {@link listMcpTools},
111
- * {@link callMcpTool}, {@link adaptMcpTools}, and {@link closeMcpSession}.
112
- * @public
113
- */
114
- export interface IMcpSession {
115
- /** Client name advertised during the handshake. */
116
- readonly clientName: string;
117
- /** Client version advertised during the handshake. */
118
- readonly clientVersion: string;
119
- /** Server identity reported by the handshake, when the server provided one. */
120
- readonly serverInfo: IMcpServerInfo | undefined;
121
- }
122
-
123
- // ============================================================================
124
- // Tool discovery + invocation
125
- // ============================================================================
126
-
127
- /**
128
- * Normalized MCP `Tool.annotations` — the five known host-advisory behavior hints.
129
- *
130
- * @remarks
131
- * Field names mirror MCP's `ToolAnnotations` 1:1 (and map straight onto
132
- * `AiAssist.IAiToolAnnotations`). Per the MCP spec these are hints only, and per the
133
- * untrusted-server warning they are validated/normalized (known fields kept, malformed
134
- * or unknown fields dropped) before they reach {@link IMcpToolDescriptor} — the raw
135
- * server blob is never propagated.
136
- *
137
- * @public
138
- */
139
- export interface IMcpToolAnnotations {
140
- /** Optional human-readable display title for the tool. */
141
- readonly title?: string;
142
- /** Hint: the tool does not modify its environment (read-only). */
143
- readonly readOnlyHint?: boolean;
144
- /** Hint: the tool may perform destructive updates (only meaningful when not read-only). */
145
- readonly destructiveHint?: boolean;
146
- /** Hint: repeated calls with the same arguments have no additional effect. */
147
- readonly idempotentHint?: boolean;
148
- /** Hint: the tool interacts with an open world of external entities. */
149
- readonly openWorldHint?: boolean;
150
- }
151
-
152
- /**
153
- * A tool descriptor discovered from an MCP server via {@link listMcpTools}.
154
- * @public
155
- */
156
- export interface IMcpToolDescriptor {
157
- /** Tool name (unique within a server). */
158
- readonly name: string;
159
- /** Human-readable description, when the server provided one. */
160
- readonly description: string | undefined;
161
- /**
162
- * The tool's declared input schema as raw JSON. Per the MCP spec this is normally a JSON
163
- * Schema object; carried verbatim so {@link adaptMcpTools} can run it through
164
- * `JsonSchema.fromJson` (and surface it on {@link IMcpSkippedTool} when it is outside the
165
- * supported subset).
166
- */
167
- readonly inputSchema: JsonValue;
168
- /**
169
- * The tool's normalized behavior annotations, when the server provided any usable ones.
170
- * Absent when the server declared no annotations (or only malformed/unknown fields).
171
- * See {@link IMcpToolAnnotations}.
172
- */
173
- readonly annotations?: IMcpToolAnnotations;
174
- }
175
-
176
- /**
177
- * Successful projection of an MCP `CallToolResult` produced by {@link callMcpTool}.
178
- *
179
- * @remarks
180
- * `content` is the text concatenation of the result's `text` blocks; non-text blocks
181
- * (image / audio / resource) are projected to a one-line `[<type> block]` summary
182
- * (multimodal passthrough is out of scope at v0.1). A result with `isError: true` is mapped
183
- * to `Result.fail(content)` rather than returned here, so it is never silently swallowed.
184
- *
185
- * @public
186
- */
187
- export interface IMcpToolCallResult {
188
- /** The projected text content of the tool result. */
189
- readonly content: string;
190
- }
191
-
192
- // ============================================================================
193
- // Adapter (Constraint 1)
194
- // ============================================================================
195
-
196
- /**
197
- * A tool that was discovered but could NOT be adapted into an `AiAssist.IAiClientTool`,
198
- * because its `inputSchema` is outside the JSON Schema subset supported by
199
- * `JsonSchema.fromJson`. Surfaced structurally so callers/the probe can enumerate exactly which
200
- * subset features a server needs (with the raw schema in hand to extend `fromJson` later).
201
- * @public
202
- */
203
- export interface IMcpSkippedTool {
204
- /** The tool's name. */
205
- readonly name: string;
206
- /** Why the tool was skipped — the JSON-pointer reason from `JsonSchema.fromJson`, or a structural reason. */
207
- readonly reason: string;
208
- /** The raw failing input schema, verbatim, in hand for additively widening `JsonSchema.fromJson`. */
209
- readonly schema: JsonValue;
210
- }
211
-
212
- /**
213
- * Options for {@link adaptMcpTools}.
214
- * @public
215
- */
216
- export interface IAdaptMcpToolsOptions {
217
- /**
218
- * Logger for the NOISY per-tool skip warnings. When a tool is skipped, a `warning` is emitted
219
- * including the tool name, the JSON-pointer reason, and the raw failing schema. When omitted,
220
- * skips are still surfaced structurally on {@link IAdaptMcpToolsResult.skipped}.
221
- */
222
- readonly logger?: Logging.ILogger;
223
- }
224
-
225
- /**
226
- * The result of {@link adaptMcpTools}: cleanly-adapted client tools plus the structurally-surfaced
227
- * set of tools that could not be adapted (graceful degradation, Constraint 1).
228
- * @public
229
- */
230
- export interface IAdaptMcpToolsResult {
231
- /** Tools adapted into `IAiClientTool` — safe to hand to `AiAssist.executeClientToolTurn`. */
232
- readonly tools: ReadonlyArray<AiAssist.IAiClientTool>;
233
- /** Tools excluded because their `inputSchema` is outside the supported JSON Schema subset. */
234
- readonly skipped: ReadonlyArray<IMcpSkippedTool>;
235
- }