@ttoss/http-server-mcp-openapi 0.6.0 → 0.7.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
@@ -89,14 +89,16 @@ repeats array values, `spaceDelimited`/`pipeDelimited` join them, and
89
89
 
90
90
  ## `registerOpenApiTools`
91
91
 
92
- | Field | Description |
93
- | ------------------- | ------------------------------------------------------------------------------------------------------------- |
94
- | `server` | The `McpServer` to register tools on. |
95
- | `spec` | One OpenAPI document, or an array of them (tools are flattened). |
96
- | `callApi` | Runs the resolved `{ method, url, body, tool, headers }` request and returns the raw data. |
97
- | `toText?` | Serialises the raw data into the tool's text payload. Defaults to pretty JSON; strings pass through verbatim. |
98
- | `serverParameters?` | Supplies server-managed path/query parameter values. See [Server-managed values](#server-managed-values). |
99
- | `options?` | See [Options](#options). |
92
+ | Field | Description |
93
+ | ---------------------- | ------------------------------------------------------------------------------------------------------------- |
94
+ | `server` | The `McpServer` to register tools on. |
95
+ | `spec` | One OpenAPI document, or an array of them (tools are flattened). |
96
+ | `callApi` | Runs the resolved `{ method, url, body, tool, headers }` request and returns the raw data. |
97
+ | `toText?` | Serialises the raw data into the tool's text payload. Defaults to pretty JSON; strings pass through verbatim. |
98
+ | `serverParameters?` | Supplies server-managed path/query parameter values. See [Server-managed values](#server-managed-values). |
99
+ | `toStructuredContent?` | `({ data, tool })` → the result's `structuredContent`, sent beside the text. `undefined` keeps it text-only. |
100
+ | `toolMeta?` | `({ tool })` → the tool's `_meta` on `tools/list`. See [MCP Apps views](#mcp-apps-views). |
101
+ | `options?` | See [Options](#options). |
100
102
 
101
103
  The default `toText` answers `NO_CONTENT_TEXT` (`Succeeded. The operation
102
104
  returned no content.`) when `callApi` resolves `undefined` or `''`, so a `204`
@@ -104,6 +106,38 @@ reaches the client as a success.
104
106
 
105
107
  Returns the list of `ToolDefinition`s that were registered.
106
108
 
109
+ ### MCP Apps views
110
+
111
+ A generated tool links to a view through `toolMeta`, and the view reads the
112
+ result from `structuredContent`:
113
+
114
+ ```typescript
115
+ import { registerAppResource } from '@ttoss/http-server-mcp';
116
+
117
+ const agentCard = registerAppResource({
118
+ server,
119
+ name: 'agent_card',
120
+ uri: 'ui://agents/card',
121
+ html: agentCardHtml,
122
+ });
123
+
124
+ registerOpenApiTools({
125
+ server,
126
+ spec,
127
+ callApi,
128
+ toolMeta: ({ tool }) => {
129
+ return tool.name === 'get-agent' ? agentCard.toolMeta() : undefined;
130
+ },
131
+ toStructuredContent: ({ data, tool }) => {
132
+ return tool.name === 'get-agent'
133
+ ? (data as Record<string, unknown>)
134
+ : undefined;
135
+ },
136
+ });
137
+ ```
138
+
139
+ Keep the text payload: a host without MCP Apps support renders only that.
140
+
107
141
  ## Calling the API In-Process
108
142
 
109
143
  When the REST API runs in the same process as the MCP server,
package/dist/index.cjs CHANGED
@@ -1183,6 +1183,9 @@ var registerOpenApiTools = args => {
1183
1183
  name: tool.name,
1184
1184
  description: tool.description,
1185
1185
  inputSchema: tool.inputSchema,
1186
+ _meta: args.toolMeta?.({
1187
+ tool
1188
+ }),
1186
1189
  handler: async rawArgs => {
1187
1190
  const headers = (0, _ttoss_http_server_mcp.getApiHeaders)();
1188
1191
  const handlerArgs = await applyServerParameters({
@@ -1192,17 +1195,25 @@ var registerOpenApiTools = args => {
1192
1195
  serverParameters: args.serverParameters
1193
1196
  });
1194
1197
  const url = tool.path(handlerArgs) + (tool.query ? tool.query(handlerArgs) : "");
1198
+ const data = await args.callApi({
1199
+ method: tool.method,
1200
+ url,
1201
+ body: tool.body ? tool.body(handlerArgs) : void 0,
1202
+ tool,
1203
+ headers
1204
+ });
1205
+ const structuredContent = args.toStructuredContent?.({
1206
+ data,
1207
+ tool
1208
+ });
1195
1209
  return {
1196
1210
  content: [{
1197
1211
  type: "text",
1198
- text: toText(await args.callApi({
1199
- method: tool.method,
1200
- url,
1201
- body: tool.body ? tool.body(handlerArgs) : void 0,
1202
- tool,
1203
- headers
1204
- }))
1205
- }]
1212
+ text: toText(data)
1213
+ }],
1214
+ ...(structuredContent === void 0 ? {} : {
1215
+ structuredContent
1216
+ })
1206
1217
  };
1207
1218
  }
1208
1219
  });
package/dist/index.d.cts CHANGED
@@ -379,6 +379,37 @@ interface RegisterOpenApiToolsArgs {
379
379
  * {@link NO_CONTENT_TEXT} for an empty body (e.g. a `204`).
380
380
  */
381
381
  toText?: (data: unknown) => string;
382
+ /**
383
+ * Builds the tool result's `structuredContent` from the raw API data, sent
384
+ * beside the text payload. Return `undefined` to keep a result text-only,
385
+ * which is every result when this is unset.
386
+ *
387
+ * @example
388
+ * ```typescript
389
+ * toStructuredContent: ({ data }) =>
390
+ * typeof data === 'object' && data !== null && !Array.isArray(data)
391
+ * ? (data as Record<string, unknown>)
392
+ * : undefined,
393
+ * ```
394
+ */
395
+ toStructuredContent?: (args: {
396
+ data: unknown;
397
+ tool: ToolDefinition;
398
+ }) => Record<string, unknown> | undefined;
399
+ /**
400
+ * Builds each tool's `_meta`, advertised on `tools/list`. This is how a
401
+ * generated tool links to an MCP Apps view: return the bag from
402
+ * `registerAppResource(...).toolMeta()`. `undefined` registers no `_meta`.
403
+ *
404
+ * @example
405
+ * ```typescript
406
+ * toolMeta: ({ tool }) =>
407
+ * tool.name === 'get-agent' ? agentCard.toolMeta() : undefined,
408
+ * ```
409
+ */
410
+ toolMeta?: (args: {
411
+ tool: ToolDefinition;
412
+ }) => Record<string, unknown> | undefined;
382
413
  /**
383
414
  * Supplies the values of the tool's server-managed path and query
384
415
  * parameters (`tool.serverManagedParameters`), keyed by their spec name.
package/dist/index.d.mts CHANGED
@@ -379,6 +379,37 @@ interface RegisterOpenApiToolsArgs {
379
379
  * {@link NO_CONTENT_TEXT} for an empty body (e.g. a `204`).
380
380
  */
381
381
  toText?: (data: unknown) => string;
382
+ /**
383
+ * Builds the tool result's `structuredContent` from the raw API data, sent
384
+ * beside the text payload. Return `undefined` to keep a result text-only,
385
+ * which is every result when this is unset.
386
+ *
387
+ * @example
388
+ * ```typescript
389
+ * toStructuredContent: ({ data }) =>
390
+ * typeof data === 'object' && data !== null && !Array.isArray(data)
391
+ * ? (data as Record<string, unknown>)
392
+ * : undefined,
393
+ * ```
394
+ */
395
+ toStructuredContent?: (args: {
396
+ data: unknown;
397
+ tool: ToolDefinition;
398
+ }) => Record<string, unknown> | undefined;
399
+ /**
400
+ * Builds each tool's `_meta`, advertised on `tools/list`. This is how a
401
+ * generated tool links to an MCP Apps view: return the bag from
402
+ * `registerAppResource(...).toolMeta()`. `undefined` registers no `_meta`.
403
+ *
404
+ * @example
405
+ * ```typescript
406
+ * toolMeta: ({ tool }) =>
407
+ * tool.name === 'get-agent' ? agentCard.toolMeta() : undefined,
408
+ * ```
409
+ */
410
+ toolMeta?: (args: {
411
+ tool: ToolDefinition;
412
+ }) => Record<string, unknown> | undefined;
382
413
  /**
383
414
  * Supplies the values of the tool's server-managed path and query
384
415
  * parameters (`tool.serverManagedParameters`), keyed by their spec name.
package/dist/index.mjs CHANGED
@@ -1180,6 +1180,9 @@ var registerOpenApiTools = args => {
1180
1180
  name: tool.name,
1181
1181
  description: tool.description,
1182
1182
  inputSchema: tool.inputSchema,
1183
+ _meta: args.toolMeta?.({
1184
+ tool
1185
+ }),
1183
1186
  handler: async rawArgs => {
1184
1187
  const headers = getApiHeaders();
1185
1188
  const handlerArgs = await applyServerParameters({
@@ -1189,17 +1192,25 @@ var registerOpenApiTools = args => {
1189
1192
  serverParameters: args.serverParameters
1190
1193
  });
1191
1194
  const url = tool.path(handlerArgs) + (tool.query ? tool.query(handlerArgs) : "");
1195
+ const data = await args.callApi({
1196
+ method: tool.method,
1197
+ url,
1198
+ body: tool.body ? tool.body(handlerArgs) : void 0,
1199
+ tool,
1200
+ headers
1201
+ });
1202
+ const structuredContent = args.toStructuredContent?.({
1203
+ data,
1204
+ tool
1205
+ });
1192
1206
  return {
1193
1207
  content: [{
1194
1208
  type: "text",
1195
- text: toText(await args.callApi({
1196
- method: tool.method,
1197
- url,
1198
- body: tool.body ? tool.body(handlerArgs) : void 0,
1199
- tool,
1200
- headers
1201
- }))
1202
- }]
1209
+ text: toText(data)
1210
+ }],
1211
+ ...(structuredContent === void 0 ? {} : {
1212
+ structuredContent
1213
+ })
1203
1214
  };
1204
1215
  }
1205
1216
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/http-server-mcp-openapi",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
4
4
  "description": "Generate Model Context Protocol (MCP) tools from an OpenAPI specification for @ttoss/http-server-mcp",
5
5
  "keywords": [
6
6
  "ai",
@@ -36,7 +36,7 @@
36
36
  ],
37
37
  "dependencies": {
38
38
  "@ttoss/http-server": "^0.11.0",
39
- "@ttoss/http-server-mcp": "^0.32.0"
39
+ "@ttoss/http-server-mcp": "^0.33.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@modelcontextprotocol/server": "^2.0.0",