@mcp-b/webmcp-types 0.2.0 → 0.3.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 (2) hide show
  1. package/README.md +127 -202
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -2,34 +2,46 @@
2
2
 
3
3
  Strict TypeScript type definitions for the WebMCP core API (`navigator.modelContext`).
4
4
 
5
- Zero dependencies. Zero runtime. Just `.d.ts` declarations.
5
+ Zero runtime. Zero side effects. Just `.d.ts` types.
6
6
 
7
- ## What's included
7
+ ## Type Safety First
8
8
 
9
- - Global `Navigator` augmentation (`navigator.modelContext`)
10
- - Core descriptors: tools
11
- - Content and result payload types (`ContentBlock`, `CallToolResult`, `ResourceContents`)
12
- - MCPB extension API types (`ModelContextExtensions`, including `callTool`)
13
- - Tool execution client types (`ModelContextClient`, `ToolExecutionContext`)
14
- - Typed event surface (`ToolCallEvent`)
15
- - Pure JSON Schema inference helpers (`JsonSchemaForInference`, `InferArgsFromInputSchema`, `ToolDescriptorFromSchema`, `ToolResultFromOutputSchema`)
9
+ This package is the type-safety source of truth for WebMCP.
10
+
11
+ - Infer tool input args from literal `inputSchema`
12
+ - Infer `structuredContent` from literal `outputSchema`
13
+ - Keep safe fallbacks (`Record<string, unknown>`) when schemas are widened/runtime-defined
14
+ - Provide name-aware typed registries with `TypedModelContext`
15
+
16
+ ## Why This Package
17
+
18
+ - Global `Navigator` augmentation for `navigator.modelContext`
19
+ - Strongly typed tool descriptors and tool responses
20
+ - Literal JSON Schema inference for tool args and `structuredContent`
21
+ - Name-aware helper types for typed tool registries
22
+ - Runtime-agnostic: works with native implementations, polyfills, or adapters
23
+
24
+ ## Package Selection
25
+
26
+ | Package | Use When |
27
+ | --- | --- |
28
+ | `@mcp-b/webmcp-types` | You only need compile-time types |
29
+ | `@mcp-b/webmcp-polyfill` | You need strict WebMCP core runtime behavior |
30
+ | `@mcp-b/global` | You want core + MCPB bridge extensions (`callTool`, prompts, resources, etc.) |
16
31
 
17
32
  ## Install
18
33
 
19
34
  ```bash
20
- npm install --save-dev @mcp-b/webmcp-types
21
- # or
22
35
  pnpm add -D @mcp-b/webmcp-types
36
+ # or
37
+ npm install --save-dev @mcp-b/webmcp-types
23
38
  ```
24
39
 
25
- If your published library exposes `@mcp-b/webmcp-types` in its own `.d.ts` surface, install it as a production dependency instead of a dev dependency.
26
-
27
- ## Usage
40
+ If your published library exposes these types in its public declarations, install as a production dependency instead of a dev dependency.
28
41
 
29
- ### Enable global types
42
+ ## Activate Global Types
30
43
 
31
- TypeScript does not always include global declarations from regular npm packages automatically.
32
- Use one of the following activation methods:
44
+ TypeScript may not automatically include global declarations from npm packages. Use one of these:
33
45
 
34
46
  1. Add to `tsconfig.json`:
35
47
 
@@ -43,145 +55,19 @@ Use one of the following activation methods:
43
55
 
44
56
  2. Add a triple-slash reference in a global `.d.ts` file:
45
57
 
46
- ```typescript
58
+ ```ts
47
59
  /// <reference types="@mcp-b/webmcp-types" />
48
60
  ```
49
61
 
50
- 3. Add a type-only import in your app/library entry:
62
+ 3. Add a type-only import:
51
63
 
52
- ```typescript
64
+ ```ts
53
65
  import type {} from '@mcp-b/webmcp-types';
54
66
  ```
55
67
 
56
- ### Global API example
57
-
58
- After activating the types, `navigator.modelContext` is available on `Navigator`:
59
-
60
- ```typescript
61
- // No import needed - types are globally augmented
62
- navigator.modelContext.registerTool({
63
- name: 'search',
64
- description: 'Search the web',
65
- inputSchema: {
66
- type: 'object',
67
- properties: { query: { type: 'string' } },
68
- required: ['query'],
69
- },
70
- execute: async ({ query }) => ({
71
- content: [{ type: 'text', text: `Results for: ${query}` }],
72
- }),
73
- });
74
- ```
75
-
76
- ### Individual imports
77
-
78
- ```typescript
79
- import type {
80
- ElicitationParams,
81
- ElicitationResult,
82
- InferArgsFromInputSchema,
83
- JsonSchemaForInference,
84
- LooseContentBlock,
85
- MaybePromise,
86
- ModelContext,
87
- ModelContextClient,
88
- ModelContextExtensions,
89
- ToolExecutionContext,
90
- ToolDescriptor,
91
- ToolDescriptorFromSchema,
92
- ToolResultFromOutputSchema,
93
- TypedModelContext,
94
- CallToolResult,
95
- } from '@mcp-b/webmcp-types';
96
- ```
97
-
98
- ### Sync or async execute handlers
99
-
100
- `execute` can return a plain result or a `Promise`.
101
-
102
- ```typescript
103
- import type { CallToolResult, ToolDescriptor } from '@mcp-b/webmcp-types';
104
-
105
- const syncTool: ToolDescriptor<{ message: string }, CallToolResult, 'sync_echo'> = {
106
- name: 'sync_echo',
107
- description: 'Synchronous echo',
108
- inputSchema: {
109
- type: 'object',
110
- properties: { message: { type: 'string' } },
111
- required: ['message'],
112
- },
113
- execute(args) {
114
- return {
115
- content: [{ type: 'text', text: args.message }],
116
- };
117
- },
118
- };
119
- ```
120
-
121
- ### Strict and loose content blocks
122
-
123
- `CallToolResult.content` accepts strict MCP content blocks and pragmatic loose objects.
124
-
125
- ```typescript
126
- import type { CallToolResult } from '@mcp-b/webmcp-types';
127
-
128
- const result: CallToolResult = {
129
- content: [
130
- { type: 'text', text: 'strict block' },
131
- { text: 'loose block', data: 'opaque payload' },
132
- ],
133
- };
134
- ```
135
-
136
- ### Typed tool descriptors
137
-
138
- ```typescript
139
- import type { ToolDescriptor } from '@mcp-b/webmcp-types';
140
-
141
- type SearchArgs = {
142
- query: string;
143
- limit?: number;
144
- };
145
-
146
- const searchTool: ToolDescriptor<SearchArgs> = {
147
- name: 'search',
148
- description: 'Search indexed docs',
149
- inputSchema: {
150
- type: 'object',
151
- properties: {
152
- query: { type: 'string' },
153
- limit: { type: 'number' },
154
- },
155
- required: ['query'],
156
- },
157
- execute: async ({ query, limit }, context) => {
158
- const approval = await context.requestUserInteraction(async () => ({
159
- confirmed: true,
160
- }));
161
-
162
- if (
163
- typeof approval !== 'object' ||
164
- !approval ||
165
- !('confirmed' in approval) ||
166
- !approval.confirmed
167
- ) {
168
- return {
169
- content: [{ type: 'text', text: 'Search cancelled by user.' }],
170
- };
171
- }
68
+ ## Quick Start
172
69
 
173
- return {
174
- content: [{ type: 'text', text: `Searching for "${query}" (limit: ${limit ?? 10})` }],
175
- };
176
- },
177
- };
178
- ```
179
-
180
- ### Pure JSON Schema inference (input + output)
181
-
182
- Inference focuses on core keywords (`type`, `properties`, `required`, `items`, `enum`, `const`) and tolerates additional schema metadata.
183
-
184
- ```typescript
70
+ ```ts
185
71
  import type { JsonSchemaForInference } from '@mcp-b/webmcp-types';
186
72
 
187
73
  const inputSchema = {
@@ -198,10 +84,7 @@ const outputSchema = {
198
84
  type: 'object',
199
85
  properties: {
200
86
  total: { type: 'integer' },
201
- items: {
202
- type: 'array',
203
- items: { type: 'string' },
204
- },
87
+ items: { type: 'array', items: { type: 'string' } },
205
88
  },
206
89
  required: ['total'],
207
90
  additionalProperties: false,
@@ -213,13 +96,11 @@ navigator.modelContext.registerTool({
213
96
  inputSchema,
214
97
  outputSchema,
215
98
  async execute(args) {
216
- // args is inferred as:
217
- // { query: string; limit?: number }
99
+ // args is inferred as: { query: string; limit?: number }
218
100
  return {
219
101
  content: [{ type: 'text', text: `Searching for ${args.query}` }],
220
- // structuredContent is inferred from outputSchema as:
221
- // { total: number; items?: string[] }
222
102
  structuredContent: {
103
+ // inferred from outputSchema
223
104
  total: 1,
224
105
  items: [args.query],
225
106
  },
@@ -228,79 +109,123 @@ navigator.modelContext.registerTool({
228
109
  });
229
110
  ```
230
111
 
231
- If your schema is not a literal (for example loaded from runtime config), inference safely falls back to `Record<string, unknown>`.
112
+ ## Strict Type Inference Deep Dive
232
113
 
233
- ### Tool-scoped elicitation
114
+ ### 1. Inference works best with literal schemas
234
115
 
235
- ```typescript
236
- import type { ModelContextExtensions } from '@mcp-b/webmcp-types';
237
-
238
- const modelContext = navigator.modelContext as Navigator['modelContext'] & ModelContextExtensions;
116
+ Use `as const satisfies JsonSchemaForInference` so TypeScript preserves literal schema information.
239
117
 
240
- modelContext.registerTool({
241
- name: 'deploy',
242
- description: 'Deploy current build',
243
- inputSchema: {
244
- type: 'object',
245
- properties: {
246
- environment: { type: 'string' },
247
- },
248
- required: ['environment'],
249
- },
250
- async execute({ environment }, context) {
251
- const confirmation = await context.requestUserInteraction(async () => ({
252
- action: 'accept',
253
- content: { confirm: true },
254
- }));
255
-
256
- if (confirmation.action !== 'accept' || !confirmation.content?.confirm) {
257
- return {
258
- content: [{ type: 'text', text: 'Deployment cancelled.' }],
259
- };
260
- }
118
+ If schema types are widened (for example `InputSchema` loaded at runtime), inference intentionally falls back to:
261
119
 
262
- return {
263
- content: [{ type: 'text', text: `Deployment started for ${environment}.` }],
264
- };
265
- },
266
- };
120
+ ```ts
121
+ Record<string, unknown>
267
122
  ```
268
123
 
269
- ### Name-aware typed context (advanced)
124
+ ### 2. Input inference rules
125
+
126
+ `InferArgsFromInputSchema<T>` and schema-driven `registerTool(...)` inference use a focused subset:
127
+
128
+ - `type`
129
+ - `properties`
130
+ - `required`
131
+ - `items`
132
+ - `enum`
133
+ - `const`
134
+ - `nullable`
135
+ - `additionalProperties`
136
+
137
+ Other schema keywords are accepted as metadata but do not add new inferred structure.
138
+
139
+ ### 3. `additionalProperties` behavior
140
+
141
+ | Schema shape | Inferred extras |
142
+ | --- | --- |
143
+ | `additionalProperties: false` | No extra keys |
144
+ | `additionalProperties` omitted/`true` | Extra keys allowed as `unknown` |
145
+ | `additionalProperties: { ... }` with no named `properties` | Map-like `Record<string, ...>` |
146
+ | `additionalProperties: { ... }` with named `properties` | Named properties inferred, extras remain `unknown` |
147
+
148
+ ### 4. Required keys depend on literal `required`
270
149
 
271
- ```typescript
150
+ If `required` is widened (for example a runtime `string[]`), fields are treated as optional by design.
151
+
152
+ ### 5. Output inference from `outputSchema`
153
+
154
+ When `outputSchema` is a literal object schema, `structuredContent` is inferred automatically via `ToolResultFromOutputSchema`.
155
+
156
+ This catches enum/type mismatches at compile time.
157
+
158
+ ### 6. Explicit typing is still available
159
+
160
+ You can always provide explicit generic args/results with `ToolDescriptor<TArgs, TResult, TName>` when schema inference is not enough for your use case.
161
+
162
+ ## Name-Aware Typed Context (Advanced)
163
+
164
+ `TypedModelContext<TTools>` gives literal-name-aware `callTool(...)` typing for known registries.
165
+
166
+ ```ts
272
167
  import type { CallToolResult, ToolDescriptor, TypedModelContext } from '@mcp-b/webmcp-types';
273
168
 
274
169
  type SearchTool = ToolDescriptor<
275
- { query: string },
170
+ { query: string; limit?: number },
276
171
  CallToolResult & { structuredContent: { total: number } },
277
172
  'search'
278
173
  >;
279
174
 
280
175
  type PingTool = ToolDescriptor<Record<string, never>, CallToolResult, 'ping'>;
281
-
282
176
  type AppModelContext = TypedModelContext<readonly [SearchTool, PingTool]>;
177
+
283
178
  declare const modelContext: AppModelContext;
284
179
 
285
- const searchResult = await modelContext.callTool({
180
+ await modelContext.callTool({
286
181
  name: 'search',
287
182
  arguments: { query: 'webmcp' },
288
183
  });
289
- // searchResult is inferred from the 'search' tool result type.
290
184
 
291
185
  await modelContext.callTool({ name: 'ping' });
292
- // 'ping' arguments are optional because the args type is Record<string, never>.
186
+ // arguments are optional for Record<string, never> tools
293
187
  ```
294
188
 
295
- ## Relationship to Runtime Packages
189
+ ## Core and Extension Surfaces
296
190
 
297
- | Package | Purpose |
298
- |---------|---------|
299
- | `@mcp-b/webmcp-types` | Type definitions only - for libraries that need to type-check against the API |
300
- | `@mcp-b/webmcp-polyfill` | Strict core runtime polyfill for `navigator.modelContext` |
301
- | `@mcp-b/global` | Full MCPB runtime (core + bridge extensions like `callTool`, prompts, resources) |
191
+ `Navigator['modelContext']` is typed as strict core WebMCP methods only.
192
+
193
+ Extension methods are available via `ModelContextExtensions` and `ModelContextWithExtensions`:
194
+
195
+ ```ts
196
+ import type { ModelContextExtensions } from '@mcp-b/webmcp-types';
197
+
198
+ const modelContext = navigator.modelContext as Navigator['modelContext'] & ModelContextExtensions;
199
+ const tools = modelContext.listTools();
200
+ const result = await modelContext.callTool({
201
+ name: 'search',
202
+ arguments: { query: 'docs' },
203
+ });
204
+
205
+ void tools;
206
+ void result;
207
+ ```
302
208
 
303
- Use `@mcp-b/webmcp-types` when you only need types (e.g., building a library that accepts `ToolDescriptor`). Use `@mcp-b/webmcp-polyfill` for strict core runtime behavior, or `@mcp-b/global` for extension-heavy bridge workflows.
209
+ ## Commonly Used Exports
210
+
211
+ | Export | Purpose |
212
+ | --- | --- |
213
+ | `ModelContext` | Strict core `navigator.modelContext` type |
214
+ | `ToolDescriptor` | Explicitly typed tool descriptor |
215
+ | `ToolDescriptorFromSchema` | Schema-driven descriptor with inferred args/result |
216
+ | `JsonSchemaForInference` | Supported JSON Schema subset for inference |
217
+ | `InferArgsFromInputSchema` | Derive args shape from a schema type |
218
+ | `ToolResultFromOutputSchema` | Derive `structuredContent` type from output schema |
219
+ | `TypedModelContext` | Name-aware typed `callTool`/`listTools` for known registries |
220
+ | `CallToolResult` | Tool response type |
221
+ | `ContentBlock` / `LooseContentBlock` | Strict and pragmatic content block typing |
222
+ | `ModelContextClient` | Tool execution client (`requestUserInteraction`) |
223
+
224
+ ## Important Notes
225
+
226
+ - This package does not install any runtime behavior.
227
+ - Runtime validation/execution behavior depends on your WebMCP runtime package.
228
+ - `navigator.modelContextTesting` is typed as optional for compatibility with Chromium preview/testing surfaces.
304
229
 
305
230
  ## License
306
231
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-b/webmcp-types",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Strict TypeScript type definitions for the WebMCP core API (navigator.modelContext)",
5
5
  "keywords": [
6
6
  "webmcp",