@mcp-web/core 0.1.0

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 (102) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +253 -0
  3. package/dist/addTool.typetest.d.ts +11 -0
  4. package/dist/addTool.typetest.d.ts.map +1 -0
  5. package/dist/addTool.typetest.js +248 -0
  6. package/dist/create-state-tools.d.ts +77 -0
  7. package/dist/create-state-tools.d.ts.map +1 -0
  8. package/dist/create-state-tools.js +181 -0
  9. package/dist/create-tool.d.ts +90 -0
  10. package/dist/create-tool.d.ts.map +1 -0
  11. package/dist/create-tool.js +82 -0
  12. package/dist/expanded-schema-tools/generate-fixed-shape-tools.d.ts +8 -0
  13. package/dist/expanded-schema-tools/generate-fixed-shape-tools.d.ts.map +1 -0
  14. package/dist/expanded-schema-tools/generate-fixed-shape-tools.js +53 -0
  15. package/dist/expanded-schema-tools/generate-fixed-shape-tools.test.d.ts +2 -0
  16. package/dist/expanded-schema-tools/generate-fixed-shape-tools.test.d.ts.map +1 -0
  17. package/dist/expanded-schema-tools/generate-fixed-shape-tools.test.js +331 -0
  18. package/dist/expanded-schema-tools/index.d.ts +4 -0
  19. package/dist/expanded-schema-tools/index.d.ts.map +1 -0
  20. package/dist/expanded-schema-tools/index.js +2 -0
  21. package/dist/expanded-schema-tools/integration.test.d.ts +2 -0
  22. package/dist/expanded-schema-tools/integration.test.d.ts.map +1 -0
  23. package/dist/expanded-schema-tools/integration.test.js +599 -0
  24. package/dist/expanded-schema-tools/schema-analysis.d.ts +18 -0
  25. package/dist/expanded-schema-tools/schema-analysis.d.ts.map +1 -0
  26. package/dist/expanded-schema-tools/schema-analysis.js +142 -0
  27. package/dist/expanded-schema-tools/schema-analysis.test.d.ts +2 -0
  28. package/dist/expanded-schema-tools/schema-analysis.test.d.ts.map +1 -0
  29. package/dist/expanded-schema-tools/schema-analysis.test.js +314 -0
  30. package/dist/expanded-schema-tools/schema-helpers.d.ts +69 -0
  31. package/dist/expanded-schema-tools/schema-helpers.d.ts.map +1 -0
  32. package/dist/expanded-schema-tools/schema-helpers.js +139 -0
  33. package/dist/expanded-schema-tools/schema-helpers.test.d.ts +2 -0
  34. package/dist/expanded-schema-tools/schema-helpers.test.d.ts.map +1 -0
  35. package/dist/expanded-schema-tools/schema-helpers.test.js +223 -0
  36. package/dist/expanded-schema-tools/tool-generator.d.ts +10 -0
  37. package/dist/expanded-schema-tools/tool-generator.d.ts.map +1 -0
  38. package/dist/expanded-schema-tools/tool-generator.js +430 -0
  39. package/dist/expanded-schema-tools/tool-generator.test.d.ts +2 -0
  40. package/dist/expanded-schema-tools/tool-generator.test.d.ts.map +1 -0
  41. package/dist/expanded-schema-tools/tool-generator.test.js +689 -0
  42. package/dist/expanded-schema-tools/types.d.ts +26 -0
  43. package/dist/expanded-schema-tools/types.d.ts.map +1 -0
  44. package/dist/expanded-schema-tools/types.js +1 -0
  45. package/dist/expanded-schema-tools/utils.d.ts +16 -0
  46. package/dist/expanded-schema-tools/utils.d.ts.map +1 -0
  47. package/dist/expanded-schema-tools/utils.js +35 -0
  48. package/dist/expanded-schema-tools/utils.test.d.ts +2 -0
  49. package/dist/expanded-schema-tools/utils.test.d.ts.map +1 -0
  50. package/dist/expanded-schema-tools/utils.test.js +169 -0
  51. package/dist/group-state.d.ts +60 -0
  52. package/dist/group-state.d.ts.map +1 -0
  53. package/dist/group-state.js +54 -0
  54. package/dist/index.d.ts +14 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +13 -0
  57. package/dist/query.d.ts +104 -0
  58. package/dist/query.d.ts.map +1 -0
  59. package/dist/query.js +128 -0
  60. package/dist/schema-helpers.d.ts +69 -0
  61. package/dist/schema-helpers.d.ts.map +1 -0
  62. package/dist/schema-helpers.js +139 -0
  63. package/dist/schemas.d.ts +140 -0
  64. package/dist/schemas.d.ts.map +1 -0
  65. package/dist/schemas.js +70 -0
  66. package/dist/tool-generators/generate-basic-state-tools.d.ts +23 -0
  67. package/dist/tool-generators/generate-basic-state-tools.d.ts.map +1 -0
  68. package/dist/tool-generators/generate-basic-state-tools.js +95 -0
  69. package/dist/tool-generators/generate-fixed-shape-tools.d.ts +8 -0
  70. package/dist/tool-generators/generate-fixed-shape-tools.d.ts.map +1 -0
  71. package/dist/tool-generators/generate-fixed-shape-tools.js +53 -0
  72. package/dist/tool-generators/index.d.ts +6 -0
  73. package/dist/tool-generators/index.d.ts.map +1 -0
  74. package/dist/tool-generators/index.js +3 -0
  75. package/dist/tool-generators/schema-analysis.d.ts +18 -0
  76. package/dist/tool-generators/schema-analysis.d.ts.map +1 -0
  77. package/dist/tool-generators/schema-analysis.js +142 -0
  78. package/dist/tool-generators/schema-helpers.d.ts +87 -0
  79. package/dist/tool-generators/schema-helpers.d.ts.map +1 -0
  80. package/dist/tool-generators/schema-helpers.js +157 -0
  81. package/dist/tool-generators/tool-generator.d.ts +11 -0
  82. package/dist/tool-generators/tool-generator.d.ts.map +1 -0
  83. package/dist/tool-generators/tool-generator.js +437 -0
  84. package/dist/tool-generators/types.d.ts +26 -0
  85. package/dist/tool-generators/types.d.ts.map +1 -0
  86. package/dist/tool-generators/types.js +1 -0
  87. package/dist/tool-generators/utils.d.ts +16 -0
  88. package/dist/tool-generators/utils.d.ts.map +1 -0
  89. package/dist/tool-generators/utils.js +35 -0
  90. package/dist/types.d.ts +17 -0
  91. package/dist/types.d.ts.map +1 -0
  92. package/dist/types.js +1 -0
  93. package/dist/utils.d.ts +31 -0
  94. package/dist/utils.d.ts.map +1 -0
  95. package/dist/utils.js +108 -0
  96. package/dist/web.d.ts +680 -0
  97. package/dist/web.d.ts.map +1 -0
  98. package/dist/web.js +1312 -0
  99. package/dist/zod-to-tools.d.ts +49 -0
  100. package/dist/zod-to-tools.d.ts.map +1 -0
  101. package/dist/zod-to-tools.js +623 -0
  102. package/package.json +58 -0
@@ -0,0 +1,26 @@
1
+ import type { ToolDefinition } from '@mcp-web/types';
2
+ import type { z } from 'zod';
3
+ export interface ToolGenerationOptions {
4
+ name: string;
5
+ description: string;
6
+ get: () => unknown;
7
+ set: (value: unknown) => void;
8
+ schema: z.ZodTypeAny;
9
+ }
10
+ export interface GeneratedTools {
11
+ tools: ToolDefinition[];
12
+ warnings: string[];
13
+ }
14
+ export interface SchemaShape {
15
+ type: 'fixed' | 'dynamic' | 'mixed' | 'unsupported';
16
+ subtype: 'object' | 'array' | 'record' | 'primitive' | 'tuple' | 'unknown';
17
+ hasOptionalFields: boolean;
18
+ optionalPaths: string[];
19
+ fixedPaths: string[];
20
+ dynamicPaths: string[];
21
+ }
22
+ export interface KeyFieldResult {
23
+ type: 'explicit' | 'none';
24
+ field?: string;
25
+ }
26
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/expanded-schema-tools/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,OAAO,CAAC;IACnB,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9B,MAAM,EAAE,CAAC,CAAC,UAAU,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,CAAC;IACpD,OAAO,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,GAAG,SAAS,CAAC;IAC3E,iBAAiB,EAAE,OAAO,CAAC;IAC3B,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Deep merge two objects recursively.
3
+ * Used for partial updates to state objects.
4
+ *
5
+ * @param target - The target object to merge into
6
+ * @param source - The source object to merge from
7
+ * @returns The merged result
8
+ *
9
+ * Key behaviors:
10
+ * - `undefined` in source → keep target value (no change)
11
+ * - `null` in source → set to null (explicit clear)
12
+ * - Nested objects → recursively merged
13
+ * - Arrays → replaced entirely (not merged)
14
+ */
15
+ export declare function deepMerge(target: unknown, source: unknown): unknown;
16
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/expanded-schema-tools/utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAenE"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Deep merge two objects recursively.
3
+ * Used for partial updates to state objects.
4
+ *
5
+ * @param target - The target object to merge into
6
+ * @param source - The source object to merge from
7
+ * @returns The merged result
8
+ *
9
+ * Key behaviors:
10
+ * - `undefined` in source → keep target value (no change)
11
+ * - `null` in source → set to null (explicit clear)
12
+ * - Nested objects → recursively merged
13
+ * - Arrays → replaced entirely (not merged)
14
+ */
15
+ export function deepMerge(target, source) {
16
+ // Base cases
17
+ if (source === null)
18
+ return source; // Explicit null clears the value
19
+ if (source === undefined)
20
+ return target; // Undefined means "no change"
21
+ if (typeof source !== 'object')
22
+ return source;
23
+ if (Array.isArray(source))
24
+ return source; // Arrays are replaced, not merged
25
+ if (typeof target !== 'object' || target === null)
26
+ return source;
27
+ if (Array.isArray(target))
28
+ return source;
29
+ // Object merge: recursively merge properties
30
+ const result = { ...target };
31
+ for (const [key, value] of Object.entries(source)) {
32
+ result[key] = deepMerge(result[key], value);
33
+ }
34
+ return result;
35
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=utils.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.test.d.ts","sourceRoot":"","sources":["../../src/expanded-schema-tools/utils.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,169 @@
1
+ import { expect, test } from 'bun:test';
2
+ import { deepMerge } from './utils.js';
3
+ // ============================================================================
4
+ // Basic Merge Cases
5
+ // ============================================================================
6
+ test('deepMerge - merges two simple objects', () => {
7
+ const target = { a: 1, b: 2 };
8
+ const source = { c: 3 };
9
+ const result = deepMerge(target, source);
10
+ expect(result).toEqual({ a: 1, b: 2, c: 3 });
11
+ });
12
+ test('deepMerge - merges with nested objects recursively', () => {
13
+ const target = {
14
+ user: { name: 'Alice', age: 30 },
15
+ settings: { theme: 'dark' },
16
+ };
17
+ const source = {
18
+ user: { age: 31, email: 'alice@example.com' },
19
+ settings: { notifications: true },
20
+ };
21
+ const result = deepMerge(target, source);
22
+ expect(result).toEqual({
23
+ user: { name: 'Alice', age: 31, email: 'alice@example.com' },
24
+ settings: { theme: 'dark', notifications: true },
25
+ });
26
+ });
27
+ test('deepMerge - merges with overlapping keys', () => {
28
+ const target = { a: 1, b: 2, c: 3 };
29
+ const source = { b: 20, c: 30 };
30
+ const result = deepMerge(target, source);
31
+ expect(result).toEqual({ a: 1, b: 20, c: 30 });
32
+ });
33
+ // ============================================================================
34
+ // Null/Undefined Handling
35
+ // ============================================================================
36
+ test('deepMerge - null in source sets value to null (explicit clear)', () => {
37
+ const target = { a: 1, b: 2 };
38
+ const source = { b: null };
39
+ const result = deepMerge(target, source);
40
+ expect(result).toEqual({ a: 1, b: null });
41
+ });
42
+ test('deepMerge - undefined in source keeps target value (no change)', () => {
43
+ const target = { a: 1, b: 2 };
44
+ const source = { b: undefined };
45
+ const result = deepMerge(target, source);
46
+ expect(result).toEqual({ a: 1, b: 2 });
47
+ });
48
+ test('deepMerge - null target, non-null source replaces with source', () => {
49
+ const target = null;
50
+ const source = { a: 1 };
51
+ const result = deepMerge(target, source);
52
+ expect(result).toEqual({ a: 1 });
53
+ });
54
+ test('deepMerge - nested null clears nested value', () => {
55
+ const target = {
56
+ user: { name: 'Alice', email: 'alice@example.com' },
57
+ };
58
+ const source = {
59
+ user: { email: null },
60
+ };
61
+ const result = deepMerge(target, source);
62
+ expect(result).toEqual({
63
+ user: { name: 'Alice', email: null },
64
+ });
65
+ });
66
+ // ============================================================================
67
+ // Array Behavior
68
+ // ============================================================================
69
+ test('deepMerge - arrays are replaced entirely (not merged)', () => {
70
+ const target = { tags: ['a', 'b', 'c'] };
71
+ const source = { tags: ['x', 'y'] };
72
+ const result = deepMerge(target, source);
73
+ expect(result).toEqual({ tags: ['x', 'y'] });
74
+ });
75
+ test('deepMerge - nested arrays within objects are replaced', () => {
76
+ const target = {
77
+ user: { name: 'Alice', tags: ['a', 'b'] },
78
+ };
79
+ const source = {
80
+ user: { tags: ['x'] },
81
+ };
82
+ const result = deepMerge(target, source);
83
+ expect(result).toEqual({
84
+ user: { name: 'Alice', tags: ['x'] },
85
+ });
86
+ });
87
+ test('deepMerge - array at root replaces target', () => {
88
+ const target = [1, 2, 3];
89
+ const source = [4, 5];
90
+ const result = deepMerge(target, source);
91
+ expect(result).toEqual([4, 5]);
92
+ });
93
+ // ============================================================================
94
+ // Edge Cases
95
+ // ============================================================================
96
+ test('deepMerge - empty objects', () => {
97
+ const target = {};
98
+ const source = {};
99
+ const result = deepMerge(target, source);
100
+ expect(result).toEqual({});
101
+ });
102
+ test('deepMerge - empty source returns target', () => {
103
+ const target = { a: 1, b: 2 };
104
+ const source = {};
105
+ const result = deepMerge(target, source);
106
+ expect(result).toEqual({ a: 1, b: 2 });
107
+ });
108
+ test('deepMerge - primitives in source replace target', () => {
109
+ const target = { a: { nested: true } };
110
+ const source = { a: 'string' };
111
+ const result = deepMerge(target, source);
112
+ expect(result).toEqual({ a: 'string' });
113
+ });
114
+ test('deepMerge - deep nesting (3+ levels)', () => {
115
+ const target = {
116
+ level1: {
117
+ level2: {
118
+ level3: {
119
+ value: 'original',
120
+ keep: true,
121
+ },
122
+ },
123
+ },
124
+ };
125
+ const source = {
126
+ level1: {
127
+ level2: {
128
+ level3: {
129
+ value: 'updated',
130
+ },
131
+ },
132
+ },
133
+ };
134
+ const result = deepMerge(target, source);
135
+ expect(result).toEqual({
136
+ level1: {
137
+ level2: {
138
+ level3: {
139
+ value: 'updated',
140
+ keep: true,
141
+ },
142
+ },
143
+ },
144
+ });
145
+ });
146
+ test('deepMerge - undefined source returns target', () => {
147
+ const target = { a: 1 };
148
+ const source = undefined;
149
+ const result = deepMerge(target, source);
150
+ expect(result).toEqual({ a: 1 });
151
+ });
152
+ test('deepMerge - primitive target and object source', () => {
153
+ const target = 'string';
154
+ const source = { a: 1 };
155
+ const result = deepMerge(target, source);
156
+ expect(result).toEqual({ a: 1 });
157
+ });
158
+ test('deepMerge - number source replaces any target', () => {
159
+ const target = { nested: { value: true } };
160
+ const source = 42;
161
+ const result = deepMerge(target, source);
162
+ expect(result).toBe(42);
163
+ });
164
+ test('deepMerge - boolean source replaces any target', () => {
165
+ const target = { a: 1 };
166
+ const source = false;
167
+ const result = deepMerge(target, source);
168
+ expect(result).toBe(false);
169
+ });
@@ -0,0 +1,60 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * A tuple representing a single piece of state: [getter, setter, schema]
4
+ * Follows the familiar [value, setter] pattern from React/Jotai hooks.
5
+ */
6
+ export type StateTriple<T> = [get: () => T, set: (value: T) => void, schema: z.ZodType<T>];
7
+ /**
8
+ * Configuration object mapping state names to their getter/setter/schema triples.
9
+ * Uses `any` instead of `unknown` to avoid contravariance issues with the setter function.
10
+ */
11
+ export type StateTriples = Record<string, StateTriple<any>>;
12
+ /**
13
+ * Infer the value type from a StateTriple.
14
+ */
15
+ type InferTripleType<T> = T extends StateTriple<infer U> ? U : never;
16
+ /**
17
+ * The result of groupState: combined schema, getter, and setter.
18
+ */
19
+ export type GroupedState<T extends StateTriples> = {
20
+ schema: z.ZodObject<{
21
+ [K in keyof T]: z.ZodOptional<T[K] extends StateTriple<infer U> ? z.ZodType<U> : never>;
22
+ }>;
23
+ get: () => {
24
+ [K in keyof T]: InferTripleType<T[K]>;
25
+ };
26
+ set: (value: Partial<{
27
+ [K in keyof T]: InferTripleType<T[K]>;
28
+ }>) => void;
29
+ };
30
+ /**
31
+ * Groups multiple atomic state variables into a single schema/getter/setter
32
+ * that can be spread into `addStateTools`.
33
+ *
34
+ * This reduces tool explosion when using declarative reactive state (like Jotai atoms)
35
+ * by exposing semantically related state through one tool set.
36
+ *
37
+ * @param atoms - Object mapping state names to [getter, setter, schema] triples
38
+ * @returns Object with combined { schema, get, set } for use with addStateTools
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * import { groupState } from '@mcp-web/core';
43
+ *
44
+ * const settingsGroup = groupState({
45
+ * sortBy: [getSortBy, setSortBy, SortBySchema],
46
+ * sortOrder: [getSortOrder, setSortOrder, SortOrderSchema],
47
+ * showCompleted: [getShowCompleted, setShowCompleted, ShowCompletedSchema],
48
+ * theme: [getTheme, setTheme, ThemeSchema],
49
+ * });
50
+ *
51
+ * mcpWeb.addStateTools({
52
+ * name: 'settings',
53
+ * description: 'Display and app settings',
54
+ * ...settingsGroup,
55
+ * });
56
+ * ```
57
+ */
58
+ export declare function groupState<T extends StateTriples>(atoms: T): GroupedState<T>;
59
+ export {};
60
+ //# sourceMappingURL=group-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group-state.d.ts","sourceRoot":"","sources":["../src/group-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAE3F;;;GAGG;AAEH,MAAM,MAAO,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;AAE7D;;GAEG;AACH,KAAK,eAAe,CAAC,CAAC,IAAI,CAAC,SAAS,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAErE;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,YAAY,IAAI;IACjD,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC;SACjB,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;KACxF,CAAC,CAAC;IACH,GAAG,EAAE,MAAM;SAAG,CAAC,IAAI,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;KAAE,CAAC;IACrD,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC;SAAG,CAAC,IAAI,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;KAAE,CAAC,KAAK,IAAI,CAAC;CAC1E,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,YAAY,EAAE,KAAK,EAAE,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CA2B5E"}
@@ -0,0 +1,54 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Groups multiple atomic state variables into a single schema/getter/setter
4
+ * that can be spread into `addStateTools`.
5
+ *
6
+ * This reduces tool explosion when using declarative reactive state (like Jotai atoms)
7
+ * by exposing semantically related state through one tool set.
8
+ *
9
+ * @param atoms - Object mapping state names to [getter, setter, schema] triples
10
+ * @returns Object with combined { schema, get, set } for use with addStateTools
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import { groupState } from '@mcp-web/core';
15
+ *
16
+ * const settingsGroup = groupState({
17
+ * sortBy: [getSortBy, setSortBy, SortBySchema],
18
+ * sortOrder: [getSortOrder, setSortOrder, SortOrderSchema],
19
+ * showCompleted: [getShowCompleted, setShowCompleted, ShowCompletedSchema],
20
+ * theme: [getTheme, setTheme, ThemeSchema],
21
+ * });
22
+ *
23
+ * mcpWeb.addStateTools({
24
+ * name: 'settings',
25
+ * description: 'Display and app settings',
26
+ * ...settingsGroup,
27
+ * });
28
+ * ```
29
+ */
30
+ export function groupState(atoms) {
31
+ // Build combined schema with all fields optional (for partial updates)
32
+ const schemaShape = {};
33
+ for (const [key, [, , schema]] of Object.entries(atoms)) {
34
+ schemaShape[key] = schema.optional();
35
+ }
36
+ const schema = z.object(schemaShape);
37
+ // Build combined getter
38
+ const get = () => {
39
+ const result = {};
40
+ for (const [key, [getter]] of Object.entries(atoms)) {
41
+ result[key] = getter();
42
+ }
43
+ return result;
44
+ };
45
+ // Build combined setter (only sets defined values)
46
+ const set = (value) => {
47
+ for (const [key, [, setter]] of Object.entries(atoms)) {
48
+ if (value[key] !== undefined) {
49
+ setter(value[key]);
50
+ }
51
+ }
52
+ };
53
+ return { schema, get, set };
54
+ }
@@ -0,0 +1,14 @@
1
+ export { QueryResponse } from './query.js';
2
+ export { id, system } from './tool-generators/index.js';
3
+ export { groupState } from './group-state.js';
4
+ export type { StateTriple, StateTriples, GroupedState } from './group-state.js';
5
+ export type { ContextItem, EphemeralContext, QueryRequest, QueryResponseResult, QueryResponseResultAccepted, QueryResponseResultComplete, QueryResponseResultFailure, QueryResponseResultProgress, } from './types.js';
6
+ export * from './utils.js';
7
+ export { MCPWeb } from './web.js';
8
+ export { createTool, isCreatedTool } from './create-tool.js';
9
+ export type { CreateToolConfig, CreatedTool } from './create-tool.js';
10
+ export { createStateTools, isCreatedStateTools } from './create-state-tools.js';
11
+ export type { CreateStateToolsConfig, CreatedStateTools, CreatedStateToolsBasic, CreatedStateToolsExpanded, } from './create-state-tools.js';
12
+ export { isCreatedApp } from '@mcp-web/types';
13
+ export type { AppDefinition, CreatedApp, ToolRegistrationError } from '@mcp-web/types';
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAExD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChF,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,mBAAmB,EACnB,2BAA2B,EAC3B,2BAA2B,EAC3B,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,YAAY,CAAC;AACpB,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGlC,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC7D,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAChF,YAAY,EACV,sBAAsB,EACtB,iBAAiB,EACjB,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ // Export query-related types
2
+ export { QueryResponse } from './query.js';
3
+ // Export schema helper functions for expanded tools
4
+ export { id, system } from './tool-generators/index.js';
5
+ // Export state grouping helper
6
+ export { groupState } from './group-state.js';
7
+ export * from './utils.js';
8
+ export { MCPWeb } from './web.js';
9
+ // Export tool creation functions (Jotai-style pattern)
10
+ export { createTool, isCreatedTool } from './create-tool.js';
11
+ export { createStateTools, isCreatedStateTools } from './create-state-tools.js';
12
+ // Re-export app-related types from @mcp-web/types for convenience
13
+ export { isCreatedApp } from '@mcp-web/types';
@@ -0,0 +1,104 @@
1
+ import type { QueryResponseResult, QueryResponseResultComplete, QueryResponseResultFailure } from './types';
2
+ /**
3
+ * Represents an in-flight query to an AI agent.
4
+ *
5
+ * QueryResponse provides multiple ways to interact with query results:
6
+ * - `stream` for fine-grained event handling
7
+ * - `result` for simple await-the-final-result usage
8
+ * - `cancel()` to abort the query
9
+ *
10
+ * @example Streaming events
11
+ * ```typescript
12
+ * const query = mcp.query({ prompt: 'Analyze the data' });
13
+ *
14
+ * for await (const event of query.stream) {
15
+ * if (event.type === 'query_progress') {
16
+ * console.log('Progress:', event.message);
17
+ * } else if (event.type === 'query_complete') {
18
+ * console.log('Done:', event.message);
19
+ * }
20
+ * }
21
+ * ```
22
+ *
23
+ * @example Simple result awaiting
24
+ * ```typescript
25
+ * const query = mcp.query({ prompt: 'Analyze the data' });
26
+ * const result = await query.result;
27
+ *
28
+ * if (result.type === 'query_complete') {
29
+ * console.log('Success:', result.message);
30
+ * }
31
+ * ```
32
+ */
33
+ export declare class QueryResponse {
34
+ #private;
35
+ /**
36
+ * Creates a new QueryResponse instance.
37
+ * @internal This is typically created by MCPWeb.query(), not directly.
38
+ */
39
+ constructor(uuid: string, stream: AsyncIterableIterator<QueryResponseResult>, cancelFn?: () => void);
40
+ /**
41
+ * Unique identifier for this query.
42
+ * Can be used to track or reference the query externally.
43
+ */
44
+ get uuid(): string;
45
+ /**
46
+ * Async iterator of query events (progress, completion, failure, cancel).
47
+ *
48
+ * Use this for fine-grained control over query lifecycle, such as
49
+ * displaying progress updates to users.
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * for await (const event of query.stream) {
54
+ * switch (event.type) {
55
+ * case 'query_progress':
56
+ * updateProgress(event.message);
57
+ * break;
58
+ * case 'query_complete':
59
+ * showResult(event);
60
+ * break;
61
+ * }
62
+ * }
63
+ * ```
64
+ */
65
+ get stream(): AsyncIterableIterator<QueryResponseResult>;
66
+ /**
67
+ * Promise that resolves to the final query result.
68
+ *
69
+ * This is a convenience property for when you only care about the final
70
+ * outcome and don't need to track progress events.
71
+ *
72
+ * @returns Promise resolving to complete or failure event
73
+ * @throws {Error} If query ends without completion or failure
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * const result = await query.result;
78
+ * if (result.type === 'query_complete') {
79
+ * console.log('Success:', result.toolCalls);
80
+ * } else {
81
+ * console.error('Failed:', result.error);
82
+ * }
83
+ * ```
84
+ */
85
+ get result(): Promise<QueryResponseResultComplete | QueryResponseResultFailure>;
86
+ /**
87
+ * Cancels the in-flight query.
88
+ *
89
+ * Triggers cancellation via AbortController or directly through the bridge,
90
+ * depending on how the query was created.
91
+ *
92
+ * @throws {Error} If cancel function is not available
93
+ *
94
+ * @example
95
+ * ```typescript
96
+ * const query = mcp.query({ prompt: 'Long task' });
97
+ *
98
+ * // Cancel after 5 seconds
99
+ * setTimeout(() => query.cancel(), 5000);
100
+ * ```
101
+ */
102
+ cancel(): void;
103
+ }
104
+ //# sourceMappingURL=query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,2BAA2B,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;AAE5G;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBAAa,aAAa;;IAKxB;;;OAGG;gBACS,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB,CAAC,mBAAmB,CAAC,EAAE,QAAQ,CAAC,EAAE,MAAM,IAAI;IAMnG;;;OAGG;IACH,IAAI,IAAI,WAEP;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,IAAI,MAAM,IAAI,qBAAqB,CAAC,mBAAmB,CAAC,CAEvD;IAED;;;;;;;;;;;;;;;;;;OAkBG;IACH,IAAI,MAAM,IAAI,OAAO,CAAC,2BAA2B,GAAG,0BAA0B,CAAC,CAS9E;IAED;;;;;;;;;;;;;;;OAeG;IACH,MAAM,IAAI,IAAI;CAOf"}
package/dist/query.js ADDED
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Represents an in-flight query to an AI agent.
3
+ *
4
+ * QueryResponse provides multiple ways to interact with query results:
5
+ * - `stream` for fine-grained event handling
6
+ * - `result` for simple await-the-final-result usage
7
+ * - `cancel()` to abort the query
8
+ *
9
+ * @example Streaming events
10
+ * ```typescript
11
+ * const query = mcp.query({ prompt: 'Analyze the data' });
12
+ *
13
+ * for await (const event of query.stream) {
14
+ * if (event.type === 'query_progress') {
15
+ * console.log('Progress:', event.message);
16
+ * } else if (event.type === 'query_complete') {
17
+ * console.log('Done:', event.message);
18
+ * }
19
+ * }
20
+ * ```
21
+ *
22
+ * @example Simple result awaiting
23
+ * ```typescript
24
+ * const query = mcp.query({ prompt: 'Analyze the data' });
25
+ * const result = await query.result;
26
+ *
27
+ * if (result.type === 'query_complete') {
28
+ * console.log('Success:', result.message);
29
+ * }
30
+ * ```
31
+ */
32
+ export class QueryResponse {
33
+ #streamIterator;
34
+ #uuid;
35
+ #cancelFn;
36
+ /**
37
+ * Creates a new QueryResponse instance.
38
+ * @internal This is typically created by MCPWeb.query(), not directly.
39
+ */
40
+ constructor(uuid, stream, cancelFn) {
41
+ this.#uuid = uuid;
42
+ this.#streamIterator = stream;
43
+ this.#cancelFn = cancelFn;
44
+ }
45
+ /**
46
+ * Unique identifier for this query.
47
+ * Can be used to track or reference the query externally.
48
+ */
49
+ get uuid() {
50
+ return this.#uuid;
51
+ }
52
+ /**
53
+ * Async iterator of query events (progress, completion, failure, cancel).
54
+ *
55
+ * Use this for fine-grained control over query lifecycle, such as
56
+ * displaying progress updates to users.
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * for await (const event of query.stream) {
61
+ * switch (event.type) {
62
+ * case 'query_progress':
63
+ * updateProgress(event.message);
64
+ * break;
65
+ * case 'query_complete':
66
+ * showResult(event);
67
+ * break;
68
+ * }
69
+ * }
70
+ * ```
71
+ */
72
+ get stream() {
73
+ return this.#streamIterator;
74
+ }
75
+ /**
76
+ * Promise that resolves to the final query result.
77
+ *
78
+ * This is a convenience property for when you only care about the final
79
+ * outcome and don't need to track progress events.
80
+ *
81
+ * @returns Promise resolving to complete or failure event
82
+ * @throws {Error} If query ends without completion or failure
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * const result = await query.result;
87
+ * if (result.type === 'query_complete') {
88
+ * console.log('Success:', result.toolCalls);
89
+ * } else {
90
+ * console.error('Failed:', result.error);
91
+ * }
92
+ * ```
93
+ */
94
+ get result() {
95
+ return (async () => {
96
+ for await (const event of this.#streamIterator) {
97
+ if (event.type === 'query_complete' || event.type === 'query_failure') {
98
+ return event;
99
+ }
100
+ }
101
+ throw new Error('Query ended without completion or failure event');
102
+ })();
103
+ }
104
+ /**
105
+ * Cancels the in-flight query.
106
+ *
107
+ * Triggers cancellation via AbortController or directly through the bridge,
108
+ * depending on how the query was created.
109
+ *
110
+ * @throws {Error} If cancel function is not available
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * const query = mcp.query({ prompt: 'Long task' });
115
+ *
116
+ * // Cancel after 5 seconds
117
+ * setTimeout(() => query.cancel(), 5000);
118
+ * ```
119
+ */
120
+ cancel() {
121
+ if (this.#cancelFn) {
122
+ this.#cancelFn();
123
+ }
124
+ else {
125
+ throw new Error('Cancel function not available for this query');
126
+ }
127
+ }
128
+ }