@frontmcp/plugins 0.2.5 → 0.3.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
@@ -1,8 +1,10 @@
1
- # MCP Gateway — Plugins
1
+ # FrontMCP Plugins
2
2
 
3
- Pluggable extensions for MCP Gateway live here. Each plugin can contribute **providers**, **hooks**, and optional **adapters** that extend the platform.
3
+ Pluggable extensions for FrontMCP live here. Each plugin can contribute **providers**, **hooks**, and optional
4
+ **adapters** that extend the platform.
4
5
 
5
- If you want to use a specific plugin, open that plugin’s README for full details. This page serves as an index and a contributor guide.
6
+ If you want to use a specific plugin, open that plugin’s README for full details. This page serves as an index and a
7
+ contributor guide.
6
8
 
7
9
  ---
8
10
 
@@ -13,13 +15,13 @@ If you want to use a specific plugin, open that plugin’s README for full detai
13
15
  - [Contributor guide: authoring a plugin](#contributor-guide-authoring-a-plugin)
14
16
  - [1) Recommended folder layout](#1-recommended-folder-layout)
15
17
  - [2) Export surface (`index.ts`)](#2-export-surface-indexts)
16
- - [3) Type augmentation for `@McpTool`](#3-type-augmentation-for-mcptool)
18
+ - [3) Extend tool metadata](#3-extend-tool-metadata)
17
19
  - [4) Implementing the plugin class](#4-implementing-the-plugin-class)
18
20
  - [5) Initialization styles (`DynamicPlugin.init`)](#5-initialization-styles-dynamicplugininit)
19
21
  - [6) Hooks contributed by plugins](#6-hooks-contributed-by-plugins)
20
22
  - [7) Registering your plugin in an app](#7-registering-your-plugin-in-an-app)
21
23
  - [8) Documentation checklist](#8-documentation-checklist)
22
- - [9) Forward-looking hook families](#9-forward-looking-hook-families)
24
+ - [9) Hook families & roadmap](#9-hook-families--roadmap)
23
25
  - [Contributing](#contributing)
24
26
  - [License](#license)
25
27
 
@@ -27,9 +29,9 @@ If you want to use a specific plugin, open that plugin’s README for full detai
27
29
 
28
30
  ## Available plugins
29
31
 
30
- | Plugin | Description | Docs | Path |
31
- |-------|-------------|------|------|
32
- | Cache | Transparent caching for tool outputs keyed by input. Supports in-memory and Redis stores; per-tool TTL and sliding windows. | [Cache Plugin README](./src/cache/README.md) | [`src/cache`](./src/cache) |
32
+ | Plugin | Description | Docs | Path |
33
+ | ------ | --------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | -------------------------- |
34
+ | Cache | Transparent caching for tool outputs keyed by input. Supports in-memory and Redis stores; per-tool TTL and sliding windows. | [Cache Plugin README](./src/cache/README.md) | [`src/cache`](./src/cache) |
33
35
 
34
36
  > For configuration and usage examples, follow the plugin’s own README.
35
37
 
@@ -39,17 +41,18 @@ If you want to use a specific plugin, open that plugin’s README for full detai
39
41
 
40
42
  ```ts
41
43
  // app.ts
42
- import { McpApp } from '@frontmcp/sdk';
43
- import CachePlugin from '@frontmcp/plugins/cache';
44
+ import { App } from '@frontmcp/sdk';
45
+ import { CachePlugin } from '@frontmcp/plugins';
44
46
 
45
- @McpApp({
46
- name: 'my-app',
47
+ @App({
48
+ id: 'my-app',
49
+ name: 'My App',
47
50
  plugins: [
48
51
  CachePlugin, // or CachePlugin.init({...}) — see below for init styles
49
52
  ],
50
53
  })
51
54
  export default class MyApp {}
52
- ````
55
+ ```
53
56
 
54
57
  ---
55
58
 
@@ -71,7 +74,8 @@ plugins/
71
74
  └─ README.md # user-facing docs
72
75
  ```
73
76
 
74
- > If your repo uses a monorepo layout like `libs/plugins/src/...`, keep the same structure under that root. Paths in this README are relative to the current `plugins` folder.
77
+ > If your repo uses a monorepo layout like `libs/plugins/src/...`, keep the same structure under that root. Paths in
78
+ > this README are relative to the current `plugins` folder.
75
79
 
76
80
  ### 2) Export surface (`index.ts`)
77
81
 
@@ -82,15 +86,16 @@ export { default } from './<your-plugin>.plugin';
82
86
  export * from './<your-plugin>.types';
83
87
  ```
84
88
 
85
- ### 3) Type augmentation for `@McpTool`
89
+ ### 3) Extend tool metadata
86
90
 
87
- If your plugin adds tool-level options (e.g., `@McpTool({ myFeature: {...} })`), augment the ambient `ToolMetadata` interface so tool authors get type-safe options.
91
+ If your plugin adds tool-level options (e.g., `cache`, `authorization`), augment the ambient
92
+ `ExtendFrontMcpToolMetadata` interface so tool authors get type-safe metadata.
88
93
 
89
94
  ```ts
90
95
  // src/my-feature/my-feature.types.ts
91
96
 
92
97
  declare global {
93
- interface ToolMetadata {
98
+ interface ExtendFrontMcpToolMetadata {
94
99
  /** Enables MyFeature for a tool; `true` uses plugin defaults. */
95
100
  myFeature?: MyFeatureToolOptions | true;
96
101
  }
@@ -106,24 +111,23 @@ export interface MyFeaturePluginOptions {
106
111
  }
107
112
  ```
108
113
 
109
- > Why: `declare global` merges into the ambient `ToolMetadata` used by `@McpTool`, so TypeScript validates options wherever tools are defined.
114
+ > Why: `declare global` merges into the ambient tool metadata used by `@Tool` / `tool(...)`, so TypeScript validates
115
+ > options wherever tools are defined.
110
116
 
111
117
  ### 4) Implementing the plugin class
112
118
 
113
- Plugins are classes decorated with `@McpPlugin(...)`. For plugins that need configuration and/or generated providers, extend `DynamicPlugin<TOptions>` so you can support both value and factory initialization while contributing dynamic providers.
119
+ Plugins are classes decorated with `@Plugin(...)`. For plugins that need configuration and/or generated providers,
120
+ extend `DynamicPlugin<TOptions>` so you can support both value and factory initialization while contributing dynamic
121
+ providers.
114
122
 
115
123
  ```ts
116
124
  // src/my-feature/my-feature.plugin.ts
117
- import {
118
- McpPlugin,
119
- DynamicPlugin,
120
- ToolHook,
121
- ToolHookStage,
122
- McpProviderType,
123
- } from '@frontmcp/sdk';
125
+ import { Plugin, DynamicPlugin, FlowHooksOf, FlowCtxOf, ProviderType } from '@frontmcp/sdk';
124
126
  import { MyFeaturePluginOptions } from './my-feature.types';
125
127
 
126
- @McpPlugin({
128
+ const ToolHook = FlowHooksOf('tools:call-tool');
129
+
130
+ @Plugin({
127
131
  name: 'plugin:my-feature',
128
132
  description: 'Does something useful',
129
133
  providers: [
@@ -137,8 +141,8 @@ export default class MyFeaturePlugin extends DynamicPlugin<MyFeaturePluginOption
137
141
  };
138
142
 
139
143
  // Contribute providers based on resolved options (runs before instance creation)
140
- static override dynamicProviders(options: MyFeaturePluginOptions): readonly McpProviderType[] {
141
- const providers: McpProviderType[] = [];
144
+ static override dynamicProviders(options: MyFeaturePluginOptions): readonly ProviderType[] {
145
+ const providers: ProviderType[] = [];
142
146
  // Decide implementations based on options
143
147
  // providers.push({ provide: MyToken, useValue: new MyProvider(options) });
144
148
  return providers;
@@ -149,9 +153,9 @@ export default class MyFeaturePlugin extends DynamicPlugin<MyFeaturePluginOption
149
153
  }
150
154
 
151
155
  // Optional: register global tool hooks contributed by the plugin
152
- @ToolHook(ToolHookStage.willExecute)
153
- async willExecute(ctx: any) {
154
- // Observe/mutate ctx.input before tool execution
156
+ @ToolHook.Will('execute', { priority: 100 })
157
+ async willExecute(ctx: FlowCtxOf<'tools:call-tool'>) {
158
+ // Observe/mutate ctx.state.toolContext before tool execution
155
159
  }
156
160
  }
157
161
  ```
@@ -160,17 +164,19 @@ export default class MyFeaturePlugin extends DynamicPlugin<MyFeaturePluginOption
160
164
 
161
165
  `DynamicPlugin` exposes a static `init()` so apps can register your plugin in different ways:
162
166
 
163
- * **Raw class** — zero-arg constructor only; no dynamic providers from options:
167
+ - **Raw class** — zero-arg constructor only; no dynamic providers from options:
164
168
 
165
169
  ```ts
166
- plugins: [MyFeaturePlugin]
170
+ plugins: [MyFeaturePlugin];
167
171
  ```
168
- * **Value style** — options known upfront; `dynamicProviders(options)` is evaluated and merged:
172
+
173
+ - **Value style** — options known upfront; `dynamicProviders(options)` is evaluated and merged:
169
174
 
170
175
  ```ts
171
- plugins: [MyFeaturePlugin.init({ defaultLevel: 'high' })]
176
+ plugins: [MyFeaturePlugin.init({ defaultLevel: 'high' })];
172
177
  ```
173
- * **Factory style** — compute options from app DI; then merge `dynamicProviders(realOptions)`:
178
+
179
+ - **Factory style** — compute options from app DI; then merge `dynamicProviders(realOptions)`:
174
180
 
175
181
  ```ts
176
182
  plugins: [
@@ -178,35 +184,51 @@ export default class MyFeaturePlugin extends DynamicPlugin<MyFeaturePluginOption
178
184
  inject: () => [SomeConfig],
179
185
  useFactory: (cfg) => ({ defaultLevel: cfg.level }),
180
186
  }),
181
- ]
187
+ ];
182
188
  ```
183
189
 
184
190
  Under the hood (high level):
185
191
 
186
- * Static providers from `@McpPlugin({ providers: [...] })` are merged first.
187
- * In **value**/**factory** styles, the registry evaluates `dynamicProviders(...)` and merges results.
188
- * Provider tokens are de-duplicated to avoid conflicts.
192
+ - Static providers from `@Plugin({ providers: [...] })` are merged first.
193
+ - In **value**/**factory** styles, the registry evaluates `dynamicProviders(...)` and merges results.
194
+ - Provider tokens are de-duplicated to avoid conflicts.
189
195
 
190
- > Implementation references (repository paths may vary):
191
- > `../common/src/plugins/dynamic.plugin.ts` and `../core/src/plugin/plugin.registry.ts`.
196
+ > Implementation references (repository paths may vary): `libs/sdk/src/common/dynamic/dynamic.plugin.ts` and
197
+ > `libs/sdk/src/plugin/plugin.registry.ts`.
192
198
 
193
199
  ### 6) Hooks contributed by plugins
194
200
 
195
- Plugins can register global tool hooks via `@ToolHook(stage)`. Hooks run for every tool unless filtered by metadata. Common stages include (examples; depends on platform version):
201
+ Plugins can register global hooks via `FlowHooksOf(...)`. The SDK exports helpers for the most common flows:
196
202
 
197
- * `willReadCache`, `willWriteCache` (see Cache plugin)
198
- * `willParseInput`, `willValidateInput`, `willExecute`, `didExecute`, `willFinalizeInvoke`
203
+ ```ts
204
+ import { ToolHook, ListToolsHook, HttpHook } from '@frontmcp/sdk';
205
+
206
+ @ToolHook.Will('validateInput')
207
+ async ensureConstraints(ctx: FlowCtxOf<'tools:call-tool'>) {
208
+ // ...
209
+ }
210
+ ```
211
+
212
+ Available hook families today include:
213
+
214
+ - `ToolHook` (`tools:call-tool`) — observe or mutate tool execution.
215
+ - `ListToolsHook` (`tools:list-tools`) — filter/augment the tool catalog during discovery.
216
+ - `HttpHook` (`http:request`) — shape raw inbound HTTP requests before flow execution.
217
+
218
+ Within each family you can register `Will`, `Stage`, `Did`, or `Around` hooks. Use `FlowCtxOf<'flow-name'>` to access
219
+ typed context/state for that flow.
199
220
 
200
221
  See the cache example hooks in: [`src/cache/cache.plugin.ts`](./src/cache/cache.plugin.ts).
201
222
 
202
223
  ### 7) Registering your plugin in an app
203
224
 
204
225
  ```ts
205
- import { McpApp } from '@frontmcp/sdk';
206
- import MyFeaturePlugin from '@frontmcp/plugins/my-feature';
226
+ import { App } from '@frontmcp/sdk';
227
+ import { MyFeaturePlugin } from '@frontmcp/plugins';
207
228
 
208
- @McpApp({
209
- name: 'my-app',
229
+ @App({
230
+ id: 'my-app',
231
+ name: 'My App',
210
232
  plugins: [
211
233
  MyFeaturePlugin, // or MyFeaturePlugin.init({...})
212
234
  ],
@@ -218,26 +240,20 @@ export default class MyApp {}
218
240
 
219
241
  Each plugin must ship a `README.md` that explains:
220
242
 
221
- * **What it does** and **when to use it**
222
- * **Installation & registration** examples (raw/value/factory)
223
- * **Configuration options** (plugin-level and tool-level)
224
- * **Providers** it contributes and any required external services
225
- * **Hooks** it adds and how they affect tool/app behavior
226
- * **Examples** (minimal and advanced)
243
+ - **What it does** and **when to use it**
244
+ - **Installation & registration** examples (raw/value/factory)
245
+ - **Configuration options** (plugin-level and tool-level)
246
+ - **Providers** it contributes and any required external services
247
+ - **Hooks** it adds and how they affect tool/app behavior
248
+ - **Examples** (minimal and advanced)
227
249
 
228
250
  For a concrete example, see the [Cache Plugin README](./src/cache/README.md).
229
251
 
230
- ### 9) Forward-looking hook families
231
-
232
- These hook families are planned. Design plugins with extension points in mind:
233
-
234
- * **AppHook** — app bootstrap/shutdown lifecycle.
235
- * **HttpHook** — inbound/outbound request/response (tracing, auditing, rate limiting, etc.).
236
- * **AuthHook** — authentication/authorization lifecycle (challenge, success, failure).
237
- * **AdapterHooks** — participate in adapter initialization/configuration.
238
- * **IO Hooks** — monitor and optionally block filesystem/native calls (policy/sandbox).
252
+ ### 9) Hook families & roadmap
239
253
 
240
- As these land, plugin authors will be able to add `@AppHook`, `@HttpHook`, `@AuthHook`, etc., similarly to `@ToolHook`.
254
+ The SDK currently exposes flow hooks for tools (`ToolHook`), tool discovery (`ListToolsHook`), and HTTP requests
255
+ (`HttpHook`). More flows (auth, transports, adapters) will land iteratively. Design plugins so you can adopt new hook
256
+ families by switching to `FlowHooksOf('<future-flow>')` as they ship.
241
257
 
242
258
  ---
243
259
 
package/package.json CHANGED
@@ -1,6 +1,25 @@
1
1
  {
2
2
  "name": "@frontmcp/plugins",
3
- "version": "0.2.5",
3
+ "version": "0.3.1",
4
+ "description": "FrontMCP plugins to extend the SDK",
5
+ "author": "AgentFront <info@agentfront.dev>",
6
+ "homepage": "https://docs.agentfront.dev",
7
+ "license": "Apache-2.0",
8
+ "keywords": [
9
+ "mcp",
10
+ "plugins",
11
+ "agentfront",
12
+ "frontmcp",
13
+ "framework",
14
+ "typescript"
15
+ ],
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/agentfront/frontmcp.git"
19
+ },
20
+ "bugs": {
21
+ "url": "https://github.com/agentfront/frontmcp/issues"
22
+ },
4
23
  "main": "./src/index.js",
5
24
  "types": "./src/index.d.ts",
6
25
  "exports": {
@@ -13,7 +32,7 @@
13
32
  },
14
33
  "dependencies": {
15
34
  "tslib": "^2.3.0",
16
- "@frontmcp/sdk": "^0.2.5"
35
+ "@frontmcp/sdk": "^0.3.1"
17
36
  },
18
37
  "type": "commonjs"
19
38
  }
@@ -6,7 +6,6 @@ const sdk_1 = require("@frontmcp/sdk");
6
6
  const cache_redis_provider_1 = tslib_1.__importDefault(require("./providers/cache-redis.provider"));
7
7
  const cache_memory_provider_1 = tslib_1.__importDefault(require("./providers/cache-memory.provider"));
8
8
  const cache_symbol_1 = require("./cache.symbol");
9
- const core_1 = require("@frontmcp/core");
10
9
  let CachePlugin = CachePlugin_1 = class CachePlugin extends sdk_1.DynamicPlugin {
11
10
  constructor(options = CachePlugin_1.defaultOptions) {
12
11
  super();
@@ -74,13 +73,13 @@ CachePlugin.defaultOptions = {
74
73
  type: 'memory',
75
74
  };
76
75
  tslib_1.__decorate([
77
- core_1.ToolHook.Will('execute', { priority: 1000 }),
76
+ sdk_1.ToolHook.Will('execute', { priority: 1000 }),
78
77
  tslib_1.__metadata("design:type", Function),
79
78
  tslib_1.__metadata("design:paramtypes", [Object]),
80
79
  tslib_1.__metadata("design:returntype", Promise)
81
80
  ], CachePlugin.prototype, "willReadCache", null);
82
81
  tslib_1.__decorate([
83
- core_1.ToolHook.Did('execute', { priority: 1000 }),
82
+ sdk_1.ToolHook.Did('execute', { priority: 1000 }),
84
83
  tslib_1.__metadata("design:type", Function),
85
84
  tslib_1.__metadata("design:paramtypes", [Object]),
86
85
  tslib_1.__metadata("design:returntype", Promise)
@@ -1 +1 @@
1
- {"version":3,"file":"cache.plugin.js","sourceRoot":"","sources":["../../../src/cache/cache.plugin.ts"],"names":[],"mappings":"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","sourcesContent":["import {DynamicPlugin, FlowCtxOf, Plugin, ProviderType} from '@frontmcp/sdk';\nimport CacheRedisProvider from './providers/cache-redis.provider';\nimport CacheMemoryProvider from './providers/cache-memory.provider';\nimport {CachePluginOptions} from './cache.types';\nimport {CacheStoreToken} from './cache.symbol';\nimport {ToolHook} from '@frontmcp/core'\n\n@Plugin({\n name: 'cache',\n description: 'Cache plugin for caching tool results',\n providers: [\n /* add providers that always loaded with the plugin or default providers */\n {\n // this is default provider for cache, will be overridden if dynamicProviders based on config\n name: 'cache:memory',\n provide: CacheStoreToken,\n useValue: new CacheMemoryProvider(60 * 60 * 24),\n },\n ],\n})\nexport default class CachePlugin extends DynamicPlugin<CachePluginOptions> {\n private readonly defaultTTL: number;\n\n static override dynamicProviders = (options: CachePluginOptions) => {\n const providers: ProviderType[] = [];\n switch (options.type) {\n case 'redis':\n case 'redis-client':\n providers.push({\n name: 'cache:redis',\n provide: CacheStoreToken,\n useValue: new CacheRedisProvider(options),\n });\n break;\n case 'memory':\n providers.push({\n name: 'cache:memory',\n provide: CacheStoreToken,\n useValue: new CacheMemoryProvider(options.defaultTTL),\n });\n break;\n }\n return providers;\n };\n\n static defaultOptions: CachePluginOptions = {\n type: 'memory',\n };\n options: CachePluginOptions;\n\n constructor(options: CachePluginOptions = CachePlugin.defaultOptions) {\n super();\n this.options = {\n defaultTTL: 60 * 60 * 24,\n ...options,\n };\n }\n\n @ToolHook.Will('execute', {priority: 1000})\n async willReadCache(flowCtx: FlowCtxOf<'tools:call-tool'>) {\n const ctx = flowCtx.state.required.toolContext;\n const {cache} = ctx.metadata;\n if (!cache || !ctx.input) {\n return;\n }\n const redis = this.get(CacheStoreToken)\n const hash = hashObject(ctx.input);\n const cached = await redis.getValue(hash);\n\n if (cache == true || (cache.ttl && cache.slideWindow)) {\n const ttl = cache === true ? this.defaultTTL : cache.ttl ?? this.defaultTTL;\n await redis.setValue(hash, cached, ttl);\n }\n\n if (cached) {\n console.log('return from cache', {cached});\n ctx.respond({\n ...cached,\n ___cached__: true,\n });\n }\n }\n\n @ToolHook.Did('execute', {priority: 1000})\n async willWriteCache(flowCtx: FlowCtxOf<'tools:call-tool'>) {\n const ctx = flowCtx.state.required.toolContext;\n const {cache} = ctx.metadata;\n if (!cache) {\n return;\n }\n const redis = this.get(CacheStoreToken)\n console.log('willWriteCache', {cache});\n const ttl = cache === true ? this.defaultTTL : cache.ttl ?? this.defaultTTL;\n\n const hash = hashObject(ctx.input!);\n await redis.setValue(hash, ctx.output, ttl);\n }\n}\n\nfunction hashObject(obj: any) {\n const keys = Object.keys(obj).sort();\n const values = keys.map(key => obj[key]);\n return values.reduce((acc, val) => {\n if (typeof val === 'object' && val !== null) {\n acc += hashObject(val);\n } else {\n acc += val;\n }\n return acc;\n }, '');\n}"]}
1
+ {"version":3,"file":"cache.plugin.js","sourceRoot":"","sources":["../../../src/cache/cache.plugin.ts"],"names":[],"mappings":"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","sourcesContent":["import {DynamicPlugin, FlowCtxOf, Plugin, ProviderType, ToolHook} from '@frontmcp/sdk';\nimport CacheRedisProvider from './providers/cache-redis.provider';\nimport CacheMemoryProvider from './providers/cache-memory.provider';\nimport {CachePluginOptions} from './cache.types';\nimport {CacheStoreToken} from './cache.symbol';\n\n\n@Plugin({\n name: 'cache',\n description: 'Cache plugin for caching tool results',\n providers: [\n /* add providers that always loaded with the plugin or default providers */\n {\n // this is default provider for cache, will be overridden if dynamicProviders based on config\n name: 'cache:memory',\n provide: CacheStoreToken,\n useValue: new CacheMemoryProvider(60 * 60 * 24),\n },\n ],\n})\nexport default class CachePlugin extends DynamicPlugin<CachePluginOptions> {\n private readonly defaultTTL: number;\n\n static override dynamicProviders = (options: CachePluginOptions) => {\n const providers: ProviderType[] = [];\n switch (options.type) {\n case 'redis':\n case 'redis-client':\n providers.push({\n name: 'cache:redis',\n provide: CacheStoreToken,\n useValue: new CacheRedisProvider(options),\n });\n break;\n case 'memory':\n providers.push({\n name: 'cache:memory',\n provide: CacheStoreToken,\n useValue: new CacheMemoryProvider(options.defaultTTL),\n });\n break;\n }\n return providers;\n };\n\n static defaultOptions: CachePluginOptions = {\n type: 'memory',\n };\n options: CachePluginOptions;\n\n constructor(options: CachePluginOptions = CachePlugin.defaultOptions) {\n super();\n this.options = {\n defaultTTL: 60 * 60 * 24,\n ...options,\n };\n }\n\n @ToolHook.Will('execute', {priority: 1000})\n async willReadCache(flowCtx: FlowCtxOf<'tools:call-tool'>) {\n const ctx = flowCtx.state.required.toolContext;\n const {cache} = ctx.metadata;\n if (!cache || !ctx.input) {\n return;\n }\n const redis = this.get(CacheStoreToken)\n const hash = hashObject(ctx.input);\n const cached = await redis.getValue(hash);\n\n if (cache == true || (cache.ttl && cache.slideWindow)) {\n const ttl = cache === true ? this.defaultTTL : cache.ttl ?? this.defaultTTL;\n await redis.setValue(hash, cached, ttl);\n }\n\n if (cached) {\n console.log('return from cache', {cached});\n ctx.respond({\n ...cached,\n ___cached__: true,\n });\n }\n }\n\n @ToolHook.Did('execute', {priority: 1000})\n async willWriteCache(flowCtx: FlowCtxOf<'tools:call-tool'>) {\n const ctx = flowCtx.state.required.toolContext;\n const {cache} = ctx.metadata;\n if (!cache) {\n return;\n }\n const redis = this.get(CacheStoreToken)\n console.log('willWriteCache', {cache});\n const ttl = cache === true ? this.defaultTTL : cache.ttl ?? this.defaultTTL;\n\n const hash = hashObject(ctx.input!);\n await redis.setValue(hash, ctx.output, ttl);\n }\n}\n\nfunction hashObject(obj: any) {\n const keys = Object.keys(obj).sort();\n const values = keys.map(key => obj[key]);\n return values.reduce((acc, val) => {\n if (typeof val === 'object' && val !== null) {\n acc += hashObject(val);\n } else {\n acc += val;\n }\n return acc;\n }, '');\n}"]}
@@ -1 +1 @@
1
- {"version":3,"file":"cache.types.js","sourceRoot":"","sources":["../../../src/cache/cache.types.ts"],"names":[],"mappings":"","sourcesContent":["import { Redis as RedisClient } from 'ioredis';\ndeclare global {\n interface ExtendFrontMcpToolMetadata {\n cache?: CachePluginToolOptions | true;\n }\n}\n\nexport interface CachePluginToolOptions {\n /**\n * Time to live in seconds. Default is 1 day.\n */\n ttl?: number; // default 1 day\n\n /**\n * If true, the cache value will be updated with the new value after the TTL.\n * Default is false.\n */\n slideWindow?: boolean;\n}\n\nexport interface BaseCachePluginOptions {\n defaultTTL?: number; // default 1 day\n}\n\nexport interface RedisClientCachePluginOptions extends BaseCachePluginOptions {\n type: 'redis-client';\n client: RedisClient;\n}\nexport interface RedisCachePluginOptions extends BaseCachePluginOptions {\n type: 'redis';\n config: {\n host: string;\n port: number;\n password?: string;\n db?: number;\n };\n}\nexport type MemoryCachePluginOptions = BaseCachePluginOptions & {\n type: 'memory';\n};\n\nexport type RedisCacheOptions = RedisClientCachePluginOptions | RedisCachePluginOptions;\n\nexport type CachePluginOptions = MemoryCachePluginOptions | RedisCacheOptions;\n\nexport interface CacheStoreInterface {\n setValue(key: string, value: any, ttlSeconds?: number): Promise<void>;\n getValue<T = any>(key: string, defaultValue?: T): Promise<T | undefined>;\n delete(key: string): Promise<void>;\n exists(key: string): Promise<boolean>;\n close(): Promise<void>;\n}\n"]}
1
+ {"version":3,"file":"cache.types.js","sourceRoot":"","sources":["../../../src/cache/cache.types.ts"],"names":[],"mappings":"","sourcesContent":["import {Redis as RedisClient} from 'ioredis';\n\ndeclare global {\n interface ExtendFrontMcpToolMetadata {\n cache?: CachePluginToolOptions | true;\n }\n}\n\nexport interface CachePluginToolOptions {\n /**\n * Time to live in seconds. Default is 1 day.\n */\n ttl?: number; // default 1 day\n\n /**\n * If true, the cache value will be updated with the new value after the TTL.\n * Default is false.\n */\n slideWindow?: boolean;\n}\n\nexport interface BaseCachePluginOptions {\n defaultTTL?: number; // default 1 day\n}\n\nexport interface RedisClientCachePluginOptions extends BaseCachePluginOptions {\n type: 'redis-client';\n client: RedisClient;\n}\n\nexport interface RedisCachePluginOptions extends BaseCachePluginOptions {\n type: 'redis';\n config: {\n host: string;\n port: number;\n password?: string;\n db?: number;\n };\n}\n\nexport type MemoryCachePluginOptions = BaseCachePluginOptions & {\n type: 'memory';\n};\n\nexport type RedisCacheOptions = RedisClientCachePluginOptions | RedisCachePluginOptions;\n\nexport type CachePluginOptions = MemoryCachePluginOptions | RedisCacheOptions;\n\nexport interface CacheStoreInterface {\n setValue(key: string, value: any, ttlSeconds?: number): Promise<void>;\n\n getValue<T = any>(key: string, defaultValue?: T): Promise<T | undefined>;\n\n delete(key: string): Promise<void>;\n\n exists(key: string): Promise<boolean>;\n\n close(): Promise<void>;\n}\n"]}