@ttoss/http-server-mcp 0.32.0 → 0.33.1

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 CHANGED
@@ -594,6 +594,19 @@ The spec suggests checking the client's declared capability before registering U
594
594
 
595
595
  Declaring it always is also strictly more compatible — a host without Apps support ignores `_meta` and renders the tool's `content`, which is the extension's own graceful-degradation contract. Keep every tool's text result meaningful on its own and the fallback takes care of itself.
596
596
 
597
+ ### Writing the view
598
+
599
+ A view is plain HTML; a raw `postMessage` client is enough, no SDK needed. Tools generated from OpenAPI link to a view through [`toolMeta` and `toStructuredContent`](https://github.com/ttoss/ttoss/tree/main/packages/http-server-mcp-openapi#mcp-apps-views). The parts that only fail inside a host:
600
+
601
+ - **The view speaks first.** It sends `ui/initialize` (`appInfo`, `appCapabilities`, `protocolVersion`), then `ui/notifications/initialized`, and reads the result from `ui/notifications/tool-result` — `structuredContent` when the tool sets it, else the text.
602
+ - **Buttons call tools through the host** with `tools/call`, and the host may ask the person to confirm. `ui/notifications/tool-input` carries the original arguments, which is what a button needs to repeat or extend the call.
603
+ - **Fonts and scripts load only from origins in `ui.csp.resourceDomains`.** The host's default CSP is `font-src 'self'`, so a `data:` font is blocked.
604
+ - **Report size from `document.body`**, not `document.documentElement`: the document is never shorter than the iframe, so the view would grow but never shrink.
605
+ - **Set every value from a tool result with `textContent`.** It is data a model or a user produced.
606
+ - **Theme from `hostContext.theme`**, updated by `ui/notifications/host-context-changed`.
607
+
608
+ To see a view, render it in a host: ext-apps' `AppBridge` in a browser works, connected before the iframe's `srcdoc` is set because the view speaks first. An agent CLI such as Claude Code is an MCP client but not an Apps host, so it never renders one.
609
+
597
610
  ## Issuing tokens for MCP clients
598
611
 
599
612
  The `auth` option above covers the **resource-server** half of MCP authorization — it verifies tokens issued by an external authorization server (Cognito, Auth0, …). To make your own first-party server _issue_ the tokens an MCP client runs the full OAuth flow against, add the [`@ttoss/http-server-auth`](https://ttoss.dev/docs/modules/packages/http-server-auth) plugin's `oauthServer()` and pair it with `createMcpRouter({ auth: { verifyToken } })` so one deployment both issues and verifies tokens. See the [OAuth Authorization Server](https://ttoss.dev/docs/engineering/guidelines/oauth-authorization-server) guideline.
@@ -716,6 +729,9 @@ The `GatedToolDef` passed to `register` has:
716
729
  - `inputSchema` — Zod field map or `ZodObject`, forwarded to `server.registerTool`.
717
730
  - `gates` (`Array<(ctx: ToolCallContext) => void | Promise<void>>`, optional) — Per-tool guards appended after the global `gates`. Receive the full `ToolCallContext` enabling arg-conditional authorization.
718
731
  - `_meta` (`Record<string, unknown>`, optional) — Tool metadata forwarded verbatim on `tools/list`; how a gated tool links to an [MCP Apps](#mcp-apps-interactive-uis) view.
732
+ - `title` (`string`, optional) — Display name forwarded on `tools/list`.
733
+ - `annotations` (`ToolAnnotations`, optional) — Behaviour hints forwarded on `tools/list`: `readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`. Clients use them to decide when to ask for confirmation; they never replace `requiredScope` or `gates`.
734
+ - `outputSchema` (Zod field map or `ZodObject`, optional) — Result schema forwarded on `tools/list`. When set, a successful result is returned as `structuredContent` **and** as the same JSON in a `TextContent` block, and the SDK validates it against the schema. Without it, the result is a single `TextContent`, as before.
719
735
  - `method` — Async handler. Receives merged call args + `buildContext` output.
720
736
 
721
737
  **`ToolCallContext`** is the object passed to gates, `buildContext`, and `onError`:
package/dist/index.cjs CHANGED
@@ -576,11 +576,15 @@ var createGatedToolRegistrar = ({
576
576
  ...extra
577
577
  });
578
578
  if (result == null) return toolError(notFoundMessage);
579
- return {
580
- content: [{
581
- type: "text",
582
- text: JSON.stringify(result)
583
- }]
579
+ const content = [{
580
+ type: "text",
581
+ text: JSON.stringify(result)
582
+ }];
583
+ return def.outputSchema === void 0 ? {
584
+ content
585
+ } : {
586
+ content,
587
+ structuredContent: result
584
588
  };
585
589
  } catch (error) {
586
590
  if (onError) await onError(error, ctx);
@@ -608,8 +612,11 @@ var createGatedToolRegistrar = ({
608
612
  return runMethod(def, ctx);
609
613
  };
610
614
  server.registerTool(def.name, {
615
+ title: def.title,
611
616
  description: def.description,
612
617
  inputSchema: def.inputSchema,
618
+ outputSchema: def.outputSchema,
619
+ annotations: def.annotations,
613
620
  _meta: def._meta
614
621
  }, handler);
615
622
  };
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  /// <reference types="node" />
3
- import { CallToolResult, InMemoryServerEventBus, McpServer, McpServer as McpServer$1, McpServerFactory, RegisteredResource, ServerEvent, ServerEventBus, ServerEventBus as ServerEventBus$1, ServerNotifier, ServerNotifier as ServerNotifier$1 } from "@modelcontextprotocol/server";
3
+ import { CallToolResult, InMemoryServerEventBus, McpServer, McpServer as McpServer$1, McpServerFactory, RegisteredResource, ServerEvent, ServerEventBus, ServerEventBus as ServerEventBus$1, ServerNotifier, ServerNotifier as ServerNotifier$1, ToolAnnotations } from "@modelcontextprotocol/server";
4
4
  import { Router } from "@ttoss/http-server";
5
5
  import accepts from "accepts";
6
6
  import { AsyncLocalStorage } from "async_hooks";
@@ -1012,7 +1012,21 @@ type ToolCallContext = {
1012
1012
  /** Definition for a single gated tool. */
1013
1013
  type GatedToolDef = {
1014
1014
  /** Tool name as registered with the MCP server. */name: string; /** Human-readable tool description. */
1015
- description: string; /** The single scope that must be present on the caller's token. */
1015
+ description: string; /** Display name shown by clients instead of `name`. */
1016
+ title?: string;
1017
+ /**
1018
+ * Behaviour hints forwarded on `tools/list` (`readOnlyHint`,
1019
+ * `destructiveHint`, `idempotentHint`, `openWorldHint`). Clients use them to
1020
+ * decide when to ask the user for confirmation; they are hints, never
1021
+ * enforcement — scope and gates still decide what may run.
1022
+ */
1023
+ annotations?: ToolAnnotations;
1024
+ /**
1025
+ * Zod field map or ZodObject describing the result. When set, a successful
1026
+ * result is also returned as `structuredContent`, and the SDK validates it
1027
+ * against this schema.
1028
+ */
1029
+ outputSchema?: unknown; /** The single scope that must be present on the caller's token. */
1016
1030
  requiredScope: string; /** Zod field map or ZodObject — passed through to `server.registerTool`. */
1017
1031
  inputSchema: unknown;
1018
1032
  /**
package/dist/index.d.mts CHANGED
@@ -2,7 +2,7 @@
2
2
  /// <reference types="node" />
3
3
  import { Router } from "@ttoss/http-server";
4
4
  import { AsyncLocalStorage } from "node:async_hooks";
5
- import { CallToolResult, InMemoryServerEventBus, McpServer, McpServer as McpServer$1, McpServerFactory, RegisteredResource, ServerEvent, ServerEventBus, ServerEventBus as ServerEventBus$1, ServerNotifier, ServerNotifier as ServerNotifier$1 } from "@modelcontextprotocol/server";
5
+ import { CallToolResult, InMemoryServerEventBus, McpServer, McpServer as McpServer$1, McpServerFactory, RegisteredResource, ServerEvent, ServerEventBus, ServerEventBus as ServerEventBus$1, ServerNotifier, ServerNotifier as ServerNotifier$1, ToolAnnotations } from "@modelcontextprotocol/server";
6
6
  import { z } from "zod";
7
7
  import accepts from "accepts";
8
8
  import { AsyncLocalStorage as AsyncLocalStorage$1 } from "async_hooks";
@@ -1013,7 +1013,21 @@ type ToolCallContext = {
1013
1013
  /** Definition for a single gated tool. */
1014
1014
  type GatedToolDef = {
1015
1015
  /** Tool name as registered with the MCP server. */name: string; /** Human-readable tool description. */
1016
- description: string; /** The single scope that must be present on the caller's token. */
1016
+ description: string; /** Display name shown by clients instead of `name`. */
1017
+ title?: string;
1018
+ /**
1019
+ * Behaviour hints forwarded on `tools/list` (`readOnlyHint`,
1020
+ * `destructiveHint`, `idempotentHint`, `openWorldHint`). Clients use them to
1021
+ * decide when to ask the user for confirmation; they are hints, never
1022
+ * enforcement — scope and gates still decide what may run.
1023
+ */
1024
+ annotations?: ToolAnnotations;
1025
+ /**
1026
+ * Zod field map or ZodObject describing the result. When set, a successful
1027
+ * result is also returned as `structuredContent`, and the SDK validates it
1028
+ * against this schema.
1029
+ */
1030
+ outputSchema?: unknown; /** The single scope that must be present on the caller's token. */
1017
1031
  requiredScope: string; /** Zod field map or ZodObject — passed through to `server.registerTool`. */
1018
1032
  inputSchema: unknown;
1019
1033
  /**
package/dist/index.mjs CHANGED
@@ -573,11 +573,15 @@ var createGatedToolRegistrar = ({
573
573
  ...extra
574
574
  });
575
575
  if (result == null) return toolError(notFoundMessage);
576
- return {
577
- content: [{
578
- type: "text",
579
- text: JSON.stringify(result)
580
- }]
576
+ const content = [{
577
+ type: "text",
578
+ text: JSON.stringify(result)
579
+ }];
580
+ return def.outputSchema === void 0 ? {
581
+ content
582
+ } : {
583
+ content,
584
+ structuredContent: result
581
585
  };
582
586
  } catch (error) {
583
587
  if (onError) await onError(error, ctx);
@@ -605,8 +609,11 @@ var createGatedToolRegistrar = ({
605
609
  return runMethod(def, ctx);
606
610
  };
607
611
  server.registerTool(def.name, {
612
+ title: def.title,
608
613
  description: def.description,
609
614
  inputSchema: def.inputSchema,
615
+ outputSchema: def.outputSchema,
616
+ annotations: def.annotations,
610
617
  _meta: def._meta
611
618
  }, handler);
612
619
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/http-server-mcp",
3
- "version": "0.32.0",
3
+ "version": "0.33.1",
4
4
  "description": "Model Context Protocol (MCP) server integration for @ttoss/http-server",
5
5
  "keywords": [
6
6
  "ai",
@@ -38,9 +38,9 @@
38
38
  "@modelcontextprotocol/server": "^2.0.0",
39
39
  "zod": "^4.4.3",
40
40
  "@ttoss/auth-core": "^0.16.0",
41
+ "@ttoss/http-server": "^0.11.0",
41
42
  "@ttoss/http-server-auth": "^0.8.0",
42
- "@ttoss/i18n-core": "^0.6.0",
43
- "@ttoss/http-server": "^0.11.0"
43
+ "@ttoss/i18n-core": "^0.6.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@modelcontextprotocol/client": "^2.0.0",