@frontmcp/adapters 0.2.1 → 0.2.3

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
@@ -1,3 +1,27 @@
1
- # FrontMcp Adapters
1
+ # FrontMCP Adapters
2
2
 
3
- TBD
3
+ This package contains adapters that extend FrontMCP servers with external capabilities by auto-generating, transforming, or delegating MCP tools.
4
+
5
+ ## Available adapters
6
+
7
+ ### OpenAPI Adapter
8
+ Generate MCP tools from an OpenAPI spec. Each operation becomes an MCP tool with strong input validation and automatic request/response handling.
9
+
10
+ - Code: `libs/adapters/src/openapi`
11
+ - README: `libs/adapters/src/openapi/README.md`
12
+ - Demo usage: `apps/demo/src/apps/expenses/index.ts`
13
+ - Example spec (used by the demo): https://frontmcp-test.proxy.beeceptor.com/openapi.json
14
+ - Generator library: https://www.npmjs.com/package/openapi-mcp-generator
15
+
16
+ Quick example:
17
+ ```ts
18
+ import { OpenapiAdapter } from '@frontmcp/adapters';
19
+
20
+ OpenapiAdapter.init({
21
+ name: 'backend:api',
22
+ url: 'https://frontmcp-test.proxy.beeceptor.com/openapi.json',
23
+ baseUrl: 'https://frontmcp-test.proxy.beeceptor.com',
24
+ });
25
+ ```
26
+
27
+ For detailed options and advanced usage, see the adapter README and the docs page `docs/adapters/openapi-adapter.mdx`.
package/package.json CHANGED
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "name": "@frontmcp/adapters",
3
- "version": "0.2.1",
4
- "type": "commonjs",
3
+ "version": "0.2.3",
5
4
  "main": "./src/index.js",
6
5
  "types": "./src/index.d.ts",
7
6
  "exports": {
@@ -14,8 +13,9 @@
14
13
  },
15
14
  "dependencies": {
16
15
  "tslib": "^2.3.0",
17
- "@frontmcp/sdk": "^0.2.1",
16
+ "@frontmcp/sdk": "^0.2.3",
18
17
  "openapi-mcp-generator": "^3.2.0",
19
18
  "json-schema-to-zod": "^2.6.1"
20
- }
19
+ },
20
+ "type": "commonjs"
21
21
  }
@@ -10,9 +10,18 @@ let OpenapiAdapter = class OpenapiAdapter extends sdk_1.DynamicAdapter {
10
10
  this.options = options;
11
11
  }
12
12
  async fetch() {
13
- const openapiLink = this.options.url;
13
+ let urlOrSpec = '';
14
+ if ('url' in this.options) {
15
+ urlOrSpec = this.options.url;
16
+ }
17
+ else if ('spec' in this.options) {
18
+ urlOrSpec = this.options.spec;
19
+ }
20
+ else {
21
+ throw new Error('Either url or spec must be provided');
22
+ }
14
23
  const { baseUrl, filterFn, defaultInclude, excludeOperationIds } = this.options;
15
- const openApiTools = await (0, openapi_mcp_generator_1.getToolsFromOpenApi)(openapiLink, {
24
+ const openApiTools = await (0, openapi_mcp_generator_1.getToolsFromOpenApi)(urlOrSpec, {
16
25
  baseUrl,
17
26
  filterFn,
18
27
  defaultInclude,
@@ -37,20 +46,4 @@ OpenapiAdapter = tslib_1.__decorate([
37
46
  tslib_1.__metadata("design:paramtypes", [Object])
38
47
  ], OpenapiAdapter);
39
48
  exports.default = OpenapiAdapter;
40
- async function withSilencedConsole(fn) {
41
- const methods = ['log', 'info', 'debug', 'warn', 'error', 'table', 'group', 'groupCollapsed', 'groupEnd', 'dir'];
42
- const originals = {};
43
- try {
44
- for (const m of methods) {
45
- originals[m] = console[m];
46
- console[m] = () => {
47
- };
48
- }
49
- return await fn;
50
- }
51
- finally {
52
- for (const m of Object.keys(originals))
53
- console[m] = originals[m];
54
- }
55
- }
56
49
  //# sourceMappingURL=openapi.adapter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"openapi.adapter.js","sourceRoot":"","sources":["../../../src/openapi/openapi.adapter.ts"],"names":[],"mappings":";;;AAAA,uCAIuB;AAEvB,iEAA6E;AAC7E,iDAAiD;AAOlC,IAAM,cAAc,GAApB,MAAM,cAAe,SAAQ,oBAAqC;IAG/E,YAAY,OAA8B;QACxC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAGD,KAAK,CAAC,KAAK;QACT,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAA;QACpC,MAAM,EAAC,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,mBAAmB,EAAC,GAAG,IAAI,CAAC,OAAO,CAAC;QAC9E,MAAM,YAAY,GAAG,MAAM,IAAA,2CAAmB,EAAC,WAAW,EAAE;YAC1D,OAAO;YACP,QAAQ;YACR,cAAc;YACd,mBAAmB;YACnB,WAAW,EAAE,KAAK;SACnB,CAAC,CAAC;QAEH,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC;SACrC,CAAC;IACJ,CAAC;IAEO,UAAU,CAAC,YAAiC;QAClD,OAAO,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;YAC7B,OAAO,IAAA,gCAAiB,EAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;IACL,CAAC;CAGF,CAAA;AAhCoB,cAAc;IAJlC,IAAA,aAAO,EAAC;QACP,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,8CAA8C;KAC5D,CAAC;;GACmB,cAAc,CAgClC;kBAhCoB,cAAc;AAkCnC,KAAK,UAAU,mBAAmB,CAAC,EAAgB;IACjD,MAAM,OAAO,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;IACjH,MAAM,SAAS,GAAG,EAAE,CAAC;IACrB,IAAI,CAAC;QACH,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YAC1B,OAAO,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE;YAClB,CAAC,CAAC;QACJ,CAAC;QACD,OAAO,MAAM,EAAE,CAAC;IAClB,CAAC;YAAS,CAAC;QACT,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IACpE,CAAC;AACH,CAAC","sourcesContent":["import {\n Adapter,\n DynamicAdapter,\n FrontMcpAdapterResponse,\n} from '@frontmcp/sdk';\nimport {OpenApiAdapterOptions} from './openapi.types';\nimport {getToolsFromOpenApi, McpToolDefinition} from 'openapi-mcp-generator';\nimport {createOpenApiTool} from \"./openapi.tool\";\n\n\n@Adapter({\n name: 'openapi',\n description: 'OpenAPI adapter that plugin for expense-mcp',\n})\nexport default class OpenapiAdapter extends DynamicAdapter<OpenApiAdapterOptions> {\n options: OpenApiAdapterOptions;\n\n constructor(options: OpenApiAdapterOptions) {\n super();\n this.options = options;\n }\n\n\n async fetch(): Promise<FrontMcpAdapterResponse> {\n const openapiLink = this.options.url\n const {baseUrl, filterFn, defaultInclude, excludeOperationIds} = this.options;\n const openApiTools = await getToolsFromOpenApi(openapiLink, {\n baseUrl,\n filterFn,\n defaultInclude,\n excludeOperationIds,\n dereference: false,\n });\n\n return {\n tools: this.parseTools(openApiTools),\n };\n }\n\n private parseTools(openApiTools: McpToolDefinition[]) {\n return openApiTools.map(tool => {\n return createOpenApiTool(tool, this.options);\n });\n }\n\n\n}\n\nasync function withSilencedConsole(fn: Promise<any>) {\n const methods = ['log', 'info', 'debug', 'warn', 'error', 'table', 'group', 'groupCollapsed', 'groupEnd', 'dir'];\n const originals = {};\n try {\n for (const m of methods) {\n originals[m] = console[m];\n console[m] = () => {\n };\n }\n return await fn;\n } finally {\n for (const m of Object.keys(originals)) console[m] = originals[m];\n }\n}\n"]}
1
+ {"version":3,"file":"openapi.adapter.js","sourceRoot":"","sources":["../../../src/openapi/openapi.adapter.ts"],"names":[],"mappings":";;;AAAA,uCAIuB;AAEvB,iEAA6E;AAC7E,iDAAiD;AAOlC,IAAM,cAAc,GAApB,MAAM,cAAe,SAAQ,oBAAqC;IAG/E,YAAY,OAA8B;QACxC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAGD,KAAK,CAAC,KAAK;QACT,IAAI,SAAS,GAAgC,EAAE,CAAA;QAC/C,IAAI,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC1B,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC;QAC/B,CAAC;aAAM,IAAI,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClC,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;QAChC,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACzD,CAAC;QACD,MAAM,EAAC,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,mBAAmB,EAAC,GAAG,IAAI,CAAC,OAAO,CAAC;QAC9E,MAAM,YAAY,GAAG,MAAM,IAAA,2CAAmB,EAAC,SAAS,EAAE;YACxD,OAAO;YACP,QAAQ;YACR,cAAc;YACd,mBAAmB;YACnB,WAAW,EAAE,KAAK;SACnB,CAAC,CAAC;QAEH,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC;SACrC,CAAC;IACJ,CAAC;IAEO,UAAU,CAAC,YAAiC;QAClD,OAAO,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;YAC7B,OAAO,IAAA,gCAAiB,EAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AArCoB,cAAc;IAJlC,IAAA,aAAO,EAAC;QACP,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,8CAA8C;KAC5D,CAAC;;GACmB,cAAc,CAqClC;kBArCoB,cAAc","sourcesContent":["import {\n Adapter,\n DynamicAdapter,\n FrontMcpAdapterResponse,\n} from '@frontmcp/sdk';\nimport {OpenApiAdapterOptions} from './openapi.types';\nimport {getToolsFromOpenApi, McpToolDefinition} from 'openapi-mcp-generator';\nimport {createOpenApiTool} from \"./openapi.tool\";\nimport {OpenAPIV3} from \"openapi-types\";\n\n@Adapter({\n name: 'openapi',\n description: 'OpenAPI adapter that plugin for expense-mcp',\n})\nexport default class OpenapiAdapter extends DynamicAdapter<OpenApiAdapterOptions> {\n options: OpenApiAdapterOptions;\n\n constructor(options: OpenApiAdapterOptions) {\n super();\n this.options = options;\n }\n\n\n async fetch(): Promise<FrontMcpAdapterResponse> {\n let urlOrSpec: string | OpenAPIV3.Document = ''\n if ('url' in this.options) {\n urlOrSpec = this.options.url;\n } else if ('spec' in this.options) {\n urlOrSpec = this.options.spec;\n } else {\n throw new Error('Either url or spec must be provided');\n }\n const {baseUrl, filterFn, defaultInclude, excludeOperationIds} = this.options;\n const openApiTools = await getToolsFromOpenApi(urlOrSpec, {\n baseUrl,\n filterFn,\n defaultInclude,\n excludeOperationIds,\n dereference: false,\n });\n\n return {\n tools: this.parseTools(openApiTools),\n };\n }\n\n private parseTools(openApiTools: McpToolDefinition[]) {\n return openApiTools.map(tool => {\n return createOpenApiTool(tool, this.options);\n });\n }\n}"]}
@@ -1,19 +1,60 @@
1
1
  import { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js";
2
2
  import { GetToolsOptions } from "openapi-mcp-generator/dist/api";
3
- export interface OpenApiAdapterOptions extends Omit<GetToolsOptions, 'dereference'> {
3
+ import { OpenAPIV3 } from "openapi-types";
4
+ interface BaseOptions extends Omit<GetToolsOptions, 'dereference'> {
5
+ /**
6
+ * The name of the adapter.
7
+ * This is used to identify the adapter in the MCP configuration.
8
+ * Also used to prefix tools if conflicted with other adapters in the same app.
9
+ */
4
10
  name: string;
5
- url: string;
11
+ /**
12
+ * The base URL of the API.
13
+ * This is used to construct the full URL for each request.
14
+ * For example, if the API is hosted at https://api.example.com/v1,
15
+ * the baseUrl should be set to https://api.example.com/v1.
16
+ */
17
+ baseUrl: string;
18
+ /**
19
+ * Additional headers to be sent with each request.
20
+ * This can be used to set authentication headers,
21
+ * such as Authorization or API Key.
22
+ */
6
23
  additionalHeaders?: Record<string, string>;
24
+ /**
25
+ * This can be used to map request information to specific
26
+ * headers as required by the API.
27
+ * For example, mapping tenantId from authenticated session payload to
28
+ * a specific header, this key will be hidden to mcp clients
29
+ * and filled by the adapter before sending the request to the API.
30
+ * @param authInfo
31
+ * @param headers
32
+ */
7
33
  headersMapper?: (authInfo: AuthInfo, headers: Headers) => Headers;
8
- bodyMapper?: (authInfo: AuthInfo, body: any) => any;
9
34
  /**
10
35
  * This can be used to map request information to specific
11
- * input schema values as required by the API.
36
+ * body values as required by the API.
12
37
  * For example, mapping tenantId from authenticated session payload to
13
- * a specific proprty in the input schema, this key will be hidden to mcp clients
38
+ * a specific property in the body, this key will be hidden to mcp clients
14
39
  * and filled by the adapter before sending the request to the API.
40
+ *
15
41
  * @param authInfo
16
- * @param request
42
+ * @param body
17
43
  */
18
- inputSchemaMapper?: (inputSchema: any) => any;
44
+ bodyMapper?: (authInfo: AuthInfo, body: any) => any;
45
+ }
46
+ interface SpecOptions extends BaseOptions {
47
+ /**
48
+ * The OpenAPI specification the OpenAPI specification.
49
+ */
50
+ spec: OpenAPIV3.Document;
51
+ }
52
+ interface UrlOptions extends BaseOptions {
53
+ /**
54
+ * The URL of the OpenAPI specification.
55
+ * Can be a local file path or a remote URL.
56
+ */
57
+ url: string;
19
58
  }
59
+ export type OpenApiAdapterOptions = SpecOptions | UrlOptions;
60
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"openapi.types.js","sourceRoot":"","sources":["../../../src/openapi/openapi.types.ts"],"names":[],"mappings":"","sourcesContent":["import {AuthInfo} from \"@modelcontextprotocol/sdk/server/auth/types.js\";\nimport {GetToolsOptions} from \"openapi-mcp-generator/dist/api\";\n\nexport interface OpenApiAdapterOptions extends Omit<GetToolsOptions, 'dereference'> {\n name: string;\n url: string;\n\n additionalHeaders?: Record<string, string>;\n headersMapper?: (authInfo: AuthInfo, headers: Headers) => Headers;\n bodyMapper?: (authInfo: AuthInfo, body: any) => any;\n /**\n * This can be used to map request information to specific\n * input schema values as required by the API.\n * For example, mapping tenantId from authenticated session payload to\n * a specific proprty in the input schema, this key will be hidden to mcp clients\n * and filled by the adapter before sending the request to the API.\n * @param authInfo\n * @param request\n */\n inputSchemaMapper?: (inputSchema: any) => any;\n}\n"]}
1
+ {"version":3,"file":"openapi.types.js","sourceRoot":"","sources":["../../../src/openapi/openapi.types.ts"],"names":[],"mappings":"","sourcesContent":["import {AuthInfo} from \"@modelcontextprotocol/sdk/server/auth/types.js\";\nimport {GetToolsOptions} from \"openapi-mcp-generator/dist/api\";\nimport {OpenAPIV3} from \"openapi-types\";\n\ninterface BaseOptions extends Omit<GetToolsOptions, 'dereference'> {\n /**\n * The name of the adapter.\n * This is used to identify the adapter in the MCP configuration.\n * Also used to prefix tools if conflicted with other adapters in the same app.\n */\n name: string;\n\n /**\n * The base URL of the API.\n * This is used to construct the full URL for each request.\n * For example, if the API is hosted at https://api.example.com/v1,\n * the baseUrl should be set to https://api.example.com/v1.\n */\n baseUrl: string;\n\n /**\n * Additional headers to be sent with each request.\n * This can be used to set authentication headers,\n * such as Authorization or API Key.\n */\n additionalHeaders?: Record<string, string>;\n /**\n * This can be used to map request information to specific\n * headers as required by the API.\n * For example, mapping tenantId from authenticated session payload to\n * a specific header, this key will be hidden to mcp clients\n * and filled by the adapter before sending the request to the API.\n * @param authInfo\n * @param headers\n */\n headersMapper?: (authInfo: AuthInfo, headers: Headers) => Headers;\n /**\n * This can be used to map request information to specific\n * body values as required by the API.\n * For example, mapping tenantId from authenticated session payload to\n * a specific property in the body, this key will be hidden to mcp clients\n * and filled by the adapter before sending the request to the API.\n *\n * @param authInfo\n * @param body\n */\n bodyMapper?: (authInfo: AuthInfo, body: any) => any;\n}\n\ninterface SpecOptions extends BaseOptions {\n /**\n * The OpenAPI specification the OpenAPI specification.\n */\n spec: OpenAPIV3.Document;\n}\n\ninterface UrlOptions extends BaseOptions {\n /**\n * The URL of the OpenAPI specification.\n * Can be a local file path or a remote URL.\n */\n url: string;\n}\n\nexport type OpenApiAdapterOptions = SpecOptions | UrlOptions;\n"]}