@frontmcp/skills 1.8.7 → 1.9.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.
- package/README.md +107 -155
- package/catalog/create-tool/examples/21-tool-with-availability-constraints.md +1 -1
- package/catalog/create-tool/references/availability.md +10 -10
- package/catalog/create-tool/references/ui-widgets.md +30 -8
- package/catalog/frontmcp-authorities/SKILL.md +5 -0
- package/catalog/frontmcp-channels/SKILL.md +17 -16
- package/catalog/frontmcp-channels/references/channel-sources.md +4 -4
- package/catalog/frontmcp-channels/references/channel-two-way.md +1 -1
- package/catalog/frontmcp-config/examples/configure-deployment-targets/distributed-ha-config.md +2 -0
- package/catalog/frontmcp-config/examples/configure-session/vercel-kv-session.md +1 -2
- package/catalog/frontmcp-config/examples/configure-transport/custom-protocol-flags.md +0 -1
- package/catalog/frontmcp-config/examples/configure-transport/distributed-sessions-redis.md +0 -1
- package/catalog/frontmcp-config/examples/configure-transport/stateless-serverless.md +2 -3
- package/catalog/frontmcp-config/examples/configure-transport-protocol-presets/stateless-api-serverless.md +2 -3
- package/catalog/frontmcp-config/references/configure-auth.md +1 -1
- package/catalog/frontmcp-config/references/configure-deployment-targets.md +54 -20
- package/catalog/frontmcp-config/references/configure-http.md +5 -2
- package/catalog/frontmcp-config/references/configure-throttle-guard-config.md +1 -1
- package/catalog/frontmcp-config/references/configure-throttle.md +4 -2
- package/catalog/frontmcp-config/references/configure-transport.md +4 -5
- package/catalog/frontmcp-deployment/SKILL.md +19 -19
- package/catalog/frontmcp-deployment/examples/deploy-to-node/docker-compose-with-redis.md +1 -1
- package/catalog/frontmcp-deployment/examples/deploy-to-node/pm2-with-nginx.md +1 -1
- package/catalog/frontmcp-deployment/references/build-for-browser.md +38 -9
- package/catalog/frontmcp-deployment/references/build-for-mcpb.md +15 -9
- package/catalog/frontmcp-deployment/references/build-for-sdk.md +2 -1
- package/catalog/frontmcp-deployment/references/deploy-to-cloudflare.md +3 -1
- package/catalog/frontmcp-deployment/references/deploy-to-lambda.md +2 -2
- package/catalog/frontmcp-deployment/references/deploy-to-node.md +11 -11
- package/catalog/frontmcp-deployment/references/mcp-client-integration.md +12 -7
- package/catalog/frontmcp-deployment/references/protocol-versions.md +7 -3
- package/catalog/frontmcp-development/examples/create-agent/nested-agents-with-swarm.md +50 -10
- package/catalog/frontmcp-development/examples/openapi-adapter/ref-security-and-filtering.md +13 -7
- package/catalog/frontmcp-development/references/create-adapter.md +14 -0
- package/catalog/frontmcp-development/references/create-agent.md +82 -49
- package/catalog/frontmcp-development/references/create-plugin-hooks.md +15 -5
- package/catalog/frontmcp-development/references/create-plugin.md +8 -4
- package/catalog/frontmcp-development/references/create-skill-with-tools.md +7 -2
- package/catalog/frontmcp-development/references/create-skill.md +4 -0
- package/catalog/frontmcp-development/references/decorators-guide.md +10 -11
- package/catalog/frontmcp-development/references/official-adapters.md +1 -1
- package/catalog/frontmcp-development/references/official-plugins.md +127 -24
- package/catalog/frontmcp-development/references/openapi-adapter.md +52 -2
- package/catalog/frontmcp-observability/references/metrics-endpoint.md +3 -1
- package/catalog/frontmcp-production-readiness/examples/distributed-ha/ha-kubernetes-3-replicas.md +12 -1
- package/catalog/frontmcp-production-readiness/references/common-checklist.md +2 -1
- package/catalog/frontmcp-production-readiness/references/distributed-ha.md +48 -28
- package/catalog/frontmcp-setup/examples/nx-workflow/build-test-affected.md +2 -2
- package/catalog/frontmcp-setup/examples/nx-workflow/multi-server-deployment.md +9 -5
- package/catalog/frontmcp-setup/examples/nx-workflow/scaffold-and-generate.md +1 -1
- package/catalog/frontmcp-setup/examples/project-structure-nx/nx-generator-scaffolding.md +1 -1
- package/catalog/frontmcp-setup/references/frontmcp-skills-usage.md +28 -15
- package/catalog/frontmcp-setup/references/multi-app-composition.md +11 -8
- package/catalog/frontmcp-setup/references/nx-workflow.md +53 -21
- package/catalog/frontmcp-setup/references/project-structure-nx.md +7 -4
- package/catalog/frontmcp-setup/references/setup-project.md +15 -0
- package/catalog/frontmcp-setup/references/setup-redis.md +12 -3
- package/catalog/frontmcp-setup/references/setup-sqlite.md +12 -8
- package/catalog/frontmcp-testing/SKILL.md +16 -12
- package/catalog/frontmcp-testing/references/setup-testing.md +14 -1
- package/catalog/skills-manifest.json +10 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,195 +1,147 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
+
<a href="https://frontmcp.dev">
|
|
3
4
|
<picture>
|
|
4
|
-
<source
|
|
5
|
-
<
|
|
6
|
-
<img width="400" alt="FrontMCP Logo" src="https://raw.githubusercontent.com/agentfront/frontmcp/refs/heads/main/docs/assets/logo/frontmcp.light.svg">
|
|
5
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/readme/hero.svg">
|
|
6
|
+
<img src="docs/assets/readme/hero.light.svg" alt="FrontMCP - The TypeScript way to build MCP servers" width="100%">
|
|
7
7
|
</picture>
|
|
8
|
-
|
|
8
|
+
</a>
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
[](https://www.npmjs.com/package/@frontmcp/sdk)
|
|
11
|
+
[](https://nodejs.org)
|
|
12
|
+
[](./LICENSE)
|
|
13
|
+
[](https://snyk.io/test/github/agentfront/frontmcp)
|
|
14
|
+
[](https://discord.gg/53AHnJnmwR)
|
|
11
15
|
|
|
12
|
-
[
|
|
13
|
-
[](https://nodejs.org)
|
|
14
|
-
[](https://github.com/agentfront/frontmcp/blob/main/LICENSE)
|
|
15
|
-
[](https://snyk.io/test/github/agentfront/frontmcp)
|
|
16
|
+
**[frontmcp.dev](https://frontmcp.dev)** · **[Learn][docs-learn]** · **[Reference][docs-reference]** · **[Examples][docs-examples]** · **[Playground][docs-playground]** · **[Blog][docs-blog]**
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
<picture>
|
|
19
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/readme/terminal.svg">
|
|
20
|
+
<img src="docs/assets/readme/terminal.light.svg" alt="npx frontmcp create my-app, then npm run dev: an MCP server running on localhost:3000" width="760">
|
|
21
|
+
</picture>
|
|
18
22
|
|
|
19
23
|
</div>
|
|
20
24
|
|
|
21
|
-
|
|
25
|
+
<br>
|
|
26
|
+
|
|
27
|
+
## Write a tool. Ship a server.
|
|
22
28
|
|
|
23
|
-
FrontMCP
|
|
24
|
-
typed, declarative framework. You write clean `@Tool`, `@Resource`, and `@App`
|
|
25
|
-
classes; FrontMCP handles the protocol, transport, dependency injection, sessions,
|
|
26
|
-
auth, and execution flow — and the **same server runs locally and ships to
|
|
27
|
-
production unchanged**.
|
|
29
|
+
Classes in, protocol out. FrontMCP handles transport, DI, sessions, auth and execution flow, and the same server runs locally and in production unchanged.
|
|
28
30
|
|
|
29
31
|
```ts
|
|
30
32
|
import 'reflect-metadata';
|
|
31
33
|
|
|
32
|
-
import { FrontMcp,
|
|
34
|
+
import { App, FrontMcp, Tool, ToolContext, z } from '@frontmcp/sdk';
|
|
35
|
+
|
|
36
|
+
@Tool({
|
|
37
|
+
name: 'add',
|
|
38
|
+
description: 'Adds two numbers together',
|
|
39
|
+
inputSchema: { a: z.number(), b: z.number() },
|
|
40
|
+
})
|
|
41
|
+
class AddTool extends ToolContext {
|
|
42
|
+
async execute(input: { a: number; b: number }) {
|
|
43
|
+
return input.a + input.b;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
33
46
|
|
|
34
|
-
|
|
47
|
+
@App({ id: 'calc', name: 'Calculator', tools: [AddTool] })
|
|
48
|
+
class CalcApp {}
|
|
35
49
|
|
|
36
50
|
@FrontMcp({
|
|
37
51
|
info: { name: 'Demo', version: '0.1.0' },
|
|
38
|
-
apps: [
|
|
52
|
+
apps: [CalcApp],
|
|
39
53
|
http: { port: 3000 },
|
|
40
|
-
logging: { level: LogLevel.Info },
|
|
41
54
|
})
|
|
42
55
|
export default class Server {}
|
|
43
56
|
```
|
|
44
57
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
- **Extensible** — plugins, lifecycle hooks, OpenAPI adapters, and external MCP sub-apps when you outgrow the defaults.
|
|
58
|
+
<div align="center">
|
|
59
|
+
<picture>
|
|
60
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/readme/features.svg">
|
|
61
|
+
<img src="docs/assets/readme/features.light.svg" alt="Typed end to end, auth built in, ship anywhere, every stage is a hook, tools with a face, one endpoint for any client" width="100%">
|
|
62
|
+
</picture>
|
|
63
|
+
</div>
|
|
52
64
|
|
|
53
|
-
|
|
65
|
+
<br>
|
|
54
66
|
|
|
55
|
-
|
|
67
|
+
## Start
|
|
56
68
|
|
|
57
69
|
```bash
|
|
58
|
-
#
|
|
59
|
-
npx frontmcp
|
|
60
|
-
|
|
61
|
-
# Existing project
|
|
62
|
-
npm i -D frontmcp @types/node@^24
|
|
63
|
-
npx frontmcp init
|
|
70
|
+
npx frontmcp create my-app # new project (Node 24+)
|
|
71
|
+
npx frontmcp init # or add FrontMCP to an existing one
|
|
64
72
|
```
|
|
65
73
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
## Capabilities
|
|
69
|
-
|
|
70
|
-
**Build** — decorator-configured [`@FrontMcp` server][docs-server] and [`@App`][docs-apps]
|
|
71
|
-
domains; typed [`@Tool`][docs-tools], [`@Resource`][docs-resources], and
|
|
72
|
-
[`@Prompt`][docs-prompts] primitives; [`@Agent`][docs-agents] multi-step chains; and
|
|
73
|
-
scoped [Providers / DI][docs-providers].
|
|
74
|
-
|
|
75
|
-
**Secure** — [Remote & Local OAuth, JWKS, DCR, per-app auth][docs-auth] with
|
|
76
|
-
stateful / stateless [sessions][docs-server] (JWT or UUID transport IDs).
|
|
77
|
-
|
|
78
|
-
**Connect & operate** — [Streamable HTTP + SSE transport][docs-transport],
|
|
79
|
-
every [MCP protocol revision][docs-protocol] from `2024-11-05` through
|
|
80
|
-
`2026-07-28` on one endpoint, capability [discovery][docs-discovery],
|
|
81
|
-
[elicitation][docs-elicitation], [hooks][docs-hooks], HTTP-discoverable
|
|
82
|
-
[skills][docs-skills], [tool UI / MCP Apps][docs-ext-apps], an in-process
|
|
83
|
-
[Direct Client][docs-direct] (`connectOpenAI` / `connectClaude`), and
|
|
84
|
-
first-class [deployment][docs-deploy].
|
|
85
|
-
|
|
86
|
-
**Extend & tooling** — official [plugins][docs-plugins] (Cache, Remember, CodeCall,
|
|
87
|
-
Dashboard), the [OpenAPI adapter][docs-adapters], a [UI library][docs-ui] (HTML/React
|
|
88
|
-
widgets, SSR, MCP Bridge), an [E2E testing framework][docs-testing], and a
|
|
89
|
-
[CLI][docs-install] (`create`, `init`, `dev`, `build`, `inspect`, `doctor`).
|
|
90
|
-
|
|
91
|
-
→ Full reference: **[docs.agentfront.dev/frontmcp][docs-home]**
|
|
74
|
+
Then follow **[Learn][docs-learn]** on [frontmcp.dev](https://frontmcp.dev), or browse [Tools][docs-tools], [Resources][docs-resources], [Prompts][docs-prompts], [Agents][docs-agents], [Auth][docs-auth], [Plugins][docs-plugins], [Tool UI][docs-ext-apps], [Testing][docs-testing] and [Deployment][docs-deploy]. Try it live in the [Playground][docs-playground].
|
|
92
75
|
|
|
93
76
|
## Packages
|
|
94
77
|
|
|
95
|
-
|
|
96
|
-
|
|
78
|
+
Install `frontmcp` (CLI) and `@frontmcp/sdk`. The rest is pulled in for you, or opt-in. Keep every `@frontmcp/*` package on the same version; a mismatch fails fast at boot ([why][docs-production]).
|
|
79
|
+
|
|
80
|
+
<details>
|
|
81
|
+
<summary><b>Core and extensions</b></summary>
|
|
82
|
+
<br>
|
|
83
|
+
|
|
84
|
+
| Package | What it does |
|
|
85
|
+
| --------------------------------------------------- | --------------------------------------------------------------- |
|
|
86
|
+
| [`frontmcp`](libs/cli) | CLI: `create`, `init`, `dev`, `build`, `inspect`, `doctor` |
|
|
87
|
+
| [`@frontmcp/sdk`](libs/sdk) | Core framework: decorators, DI, flows, transport, MCP protocol |
|
|
88
|
+
| [`@frontmcp/auth`](libs/auth) | OAuth, JWKS, DCR/CIMD, sessions, credential vault |
|
|
89
|
+
| [`@frontmcp/testing`](libs/testing) | E2E test framework with fixtures and matchers |
|
|
90
|
+
| [`@frontmcp/adapters`](libs/adapters) | Generate tools from an OpenAPI spec |
|
|
91
|
+
| [`@frontmcp/skills`](libs/skills) | Curated `SKILL.md` catalog for scaffolding and `skills install` |
|
|
92
|
+
| [`@frontmcp/guard`](libs/guard) | Rate limits, concurrency and policy guards |
|
|
93
|
+
| [`@frontmcp/observability`](libs/observability) | Structured logging, metrics and tracing |
|
|
94
|
+
| [`@frontmcp/react`](libs/react) | React hooks and client for a FrontMCP server |
|
|
95
|
+
| [`@frontmcp/ui`](libs/ui) / [`uipack`](libs/uipack) | Widgets, SSR renderers, MCP Bridge, themes |
|
|
96
|
+
| [`@frontmcp/edge`](libs/edge) | Run a server on Cloudflare Workers / V8 isolates |
|
|
97
|
+
| [`@frontmcp/storage-sqlite`](libs/storage-sqlite) | SQLite session, task and elicitation stores |
|
|
98
|
+
| [`@frontmcp/nx`](libs/nx-plugin) | Nx generators and executors |
|
|
99
|
+
|
|
100
|
+
Internal, published so the above resolve: [`protocol`](libs/protocol), [`di`](libs/di), [`utils`](libs/utils), [`lazy-zod`](libs/lazy-zod).
|
|
101
|
+
|
|
102
|
+
</details>
|
|
103
|
+
|
|
104
|
+
<details>
|
|
105
|
+
<summary><b>Official plugins</b></summary>
|
|
106
|
+
<br>
|
|
107
|
+
|
|
108
|
+
| Package | What it does |
|
|
109
|
+
| -------------------------------------------------------------------- | ----------------------------------------------- |
|
|
110
|
+
| [`@frontmcp/plugin-cache`](plugins/plugin-cache) | Cache tool results with a TTL |
|
|
111
|
+
| [`@frontmcp/plugin-remember`](plugins/plugin-remember) | Per-session memory (`this.remember`) |
|
|
112
|
+
| [`@frontmcp/plugin-approval`](plugins/plugin-approval) | Human approval gates before a tool runs |
|
|
113
|
+
| [`@frontmcp/plugin-codecall`](plugins/plugin-codecall) | Let the model compose tool calls as code |
|
|
114
|
+
| [`@frontmcp/plugin-dashboard`](plugins/plugin-dashboard) | Built-in web dashboard |
|
|
115
|
+
| [`@frontmcp/plugin-feature-flags`](plugins/plugin-feature-flags) | Toggle tools and apps at runtime |
|
|
116
|
+
| [`@frontmcp/plugin-skilled-openapi`](plugins/plugin-skilled-openapi) | OpenAPI to skills and meta-tools for big APIs |
|
|
117
|
+
| [`@frontmcp/plugin-webmcp`](plugins/plugin-webmcp) | Expose in-page tools to browser agents (WebMCP) |
|
|
118
|
+
|
|
119
|
+
</details>
|
|
120
|
+
|
|
121
|
+
<br>
|
|
97
122
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
| Package | Description |
|
|
101
|
-
| ----------------------------------- | --------------------------------------------------------------- |
|
|
102
|
-
| [`frontmcp`](libs/cli) | The CLI — `create`, `init`, `dev`, `build`, `inspect`, `doctor` |
|
|
103
|
-
| [`@frontmcp/sdk`](libs/sdk) | Core framework — decorators, DI, flows, transport, MCP protocol |
|
|
104
|
-
| [`@frontmcp/auth`](libs/auth) | Authentication, OAuth, JWKS, DCR/CIMD, credential vault |
|
|
105
|
-
| [`@frontmcp/testing`](libs/testing) | E2E test framework with fixtures and matchers |
|
|
106
|
-
|
|
107
|
-
### Extend
|
|
108
|
-
|
|
109
|
-
| Package | Description |
|
|
110
|
-
| ----------------------------------------------- | ------------------------------------------------------------- |
|
|
111
|
-
| [`@frontmcp/plugins`](libs/plugins) | Plugin authoring toolkit + official plugin re-exports |
|
|
112
|
-
| [`@frontmcp/adapters`](libs/adapters) | OpenAPI adapter — generate tools from an OpenAPI spec |
|
|
113
|
-
| [`@frontmcp/skills`](libs/skills) | Curated SKILL.md catalog for scaffolding and `skills install` |
|
|
114
|
-
| [`@frontmcp/guard`](libs/guard) | Policy/guard rules for tool inputs and outputs |
|
|
115
|
-
| [`@frontmcp/observability`](libs/observability) | Structured logging, metrics, and tracing helpers |
|
|
116
|
-
|
|
117
|
-
### UI
|
|
118
|
-
|
|
119
|
-
| Package | Description |
|
|
120
|
-
| --------------------------------- | ----------------------------------------------------- |
|
|
121
|
-
| [`@frontmcp/react`](libs/react) | React hooks + client for talking to a FrontMCP server |
|
|
122
|
-
| [`@frontmcp/ui`](libs/ui) | React components, SSR renderers, MCP Bridge |
|
|
123
|
-
| [`@frontmcp/uipack`](libs/uipack) | React-free themes, build tools, platform adapters |
|
|
124
|
-
|
|
125
|
-
### Runtime & storage
|
|
126
|
-
|
|
127
|
-
| Package | Description |
|
|
128
|
-
| ------------------------------------------------- | -------------------------------------------------------------- |
|
|
129
|
-
| [`@frontmcp/edge`](libs/edge) | Run a server on Cloudflare Workers / V8 isolates from a config |
|
|
130
|
-
| [`@frontmcp/storage-sqlite`](libs/storage-sqlite) | SQLite-backed session, task, and elicitation stores |
|
|
131
|
-
| [`@frontmcp/nx`](libs/nx-plugin) | Nx generators and executors for FrontMCP workspaces |
|
|
132
|
-
|
|
133
|
-
### Internal
|
|
134
|
-
|
|
135
|
-
Published so the packages above resolve, but not intended for direct use:
|
|
136
|
-
|
|
137
|
-
| Package | Description |
|
|
138
|
-
| ------------------------------------- | ------------------------------------------------------------ |
|
|
139
|
-
| [`@frontmcp/protocol`](libs/protocol) | The single boundary to the upstream MCP SDK — protocol types |
|
|
140
|
-
| [`@frontmcp/di`](libs/di) | Dependency injection container |
|
|
141
|
-
| [`@frontmcp/utils`](libs/utils) | Shared utilities — naming, URI, crypto, FS |
|
|
142
|
-
| [`@frontmcp/lazy-zod`](libs/lazy-zod) | Lazily-loaded Zod wrapper that keeps cold starts small |
|
|
143
|
-
|
|
144
|
-
### Official plugins
|
|
145
|
-
|
|
146
|
-
| Package | Description |
|
|
147
|
-
| -------------------------------------------------------------------- | -------------------------------------------- |
|
|
148
|
-
| [`@frontmcp/plugin-cache`](plugins/plugin-cache) | Cache tool results with a TTL |
|
|
149
|
-
| [`@frontmcp/plugin-remember`](plugins/plugin-remember) | Per-session memory (`this.remember`) |
|
|
150
|
-
| [`@frontmcp/plugin-approval`](plugins/plugin-approval) | Human approval gates before a tool runs |
|
|
151
|
-
| [`@frontmcp/plugin-codecall`](plugins/plugin-codecall) | Let the model compose tool calls as code |
|
|
152
|
-
| [`@frontmcp/plugin-dashboard`](plugins/plugin-dashboard) | Built-in web dashboard |
|
|
153
|
-
| [`@frontmcp/plugin-feature-flags`](plugins/plugin-feature-flags) | Toggle tools and apps at runtime |
|
|
154
|
-
| [`@frontmcp/plugin-skilled-openapi`](plugins/plugin-skilled-openapi) | OpenAPI → skills + meta-tools for large APIs |
|
|
155
|
-
|
|
156
|
-
## Version Alignment
|
|
157
|
-
|
|
158
|
-
Keep all `@frontmcp/*` packages on the same version. A clear **"version mismatch"** error is thrown at boot if versions drift. ([Production Build][docs-production])
|
|
159
|
-
|
|
160
|
-
## Contributing
|
|
123
|
+
<div align="center">
|
|
161
124
|
|
|
162
|
-
PRs welcome
|
|
125
|
+
PRs welcome: see [CONTRIBUTING](./CONTRIBUTING.md). Released under the [Apache-2.0](./LICENSE) license.
|
|
163
126
|
|
|
164
|
-
|
|
127
|
+
Docs also mirrored at [docs.agentfront.dev/frontmcp](https://docs.agentfront.dev/frontmcp).
|
|
165
128
|
|
|
166
|
-
|
|
129
|
+
</div>
|
|
167
130
|
|
|
168
131
|
<!-- docs links -->
|
|
169
132
|
|
|
170
|
-
[docs-
|
|
171
|
-
[docs-
|
|
172
|
-
[docs-
|
|
173
|
-
[docs-
|
|
174
|
-
[docs-
|
|
175
|
-
[docs-
|
|
176
|
-
[docs-
|
|
177
|
-
[docs-
|
|
178
|
-
[docs-
|
|
179
|
-
[docs-
|
|
180
|
-
[docs-
|
|
181
|
-
[docs-
|
|
182
|
-
[docs-
|
|
183
|
-
[docs-
|
|
184
|
-
[docs-
|
|
185
|
-
[docs-direct]: https://docs.agentfront.dev/frontmcp/deployment/direct-client 'Direct Client'
|
|
186
|
-
[docs-transport]: https://docs.agentfront.dev/frontmcp/deployment/transport-security 'Transport'
|
|
187
|
-
[docs-ext-apps]: https://docs.agentfront.dev/frontmcp/guides/building-tool-ui 'Tool UI / MCP Apps'
|
|
188
|
-
[docs-hooks]: https://docs.agentfront.dev/frontmcp/sdk-reference/decorators/hooks 'Hooks'
|
|
189
|
-
[docs-providers]: https://docs.agentfront.dev/frontmcp/extensibility/providers 'Providers'
|
|
190
|
-
[docs-plugins]: https://docs.agentfront.dev/frontmcp/plugins/overview 'Plugins'
|
|
191
|
-
[docs-adapters]: https://docs.agentfront.dev/frontmcp/adapters/overview 'Adapters'
|
|
192
|
-
[docs-testing]: https://docs.agentfront.dev/frontmcp/testing/overview 'Testing'
|
|
193
|
-
[docs-ui]: https://docs.agentfront.dev/frontmcp/react/overview 'React SDK'
|
|
194
|
-
[docs-deploy]: https://docs.agentfront.dev/frontmcp/deployment/local-dev-server 'Deployment'
|
|
195
|
-
[docs-production]: https://docs.agentfront.dev/frontmcp/deployment/production-build 'Production Build'
|
|
133
|
+
[docs-learn]: https://frontmcp.dev/learn 'Learn FrontMCP'
|
|
134
|
+
[docs-reference]: https://frontmcp.dev/reference 'Reference'
|
|
135
|
+
[docs-examples]: https://frontmcp.dev/examples 'Examples'
|
|
136
|
+
[docs-playground]: https://frontmcp.dev/playground 'Playground'
|
|
137
|
+
[docs-blog]: https://frontmcp.dev/blog 'Blog'
|
|
138
|
+
[docs-tools]: https://frontmcp.dev/reference/sdk/tool 'Tools'
|
|
139
|
+
[docs-resources]: https://frontmcp.dev/reference/sdk/resource 'Resources'
|
|
140
|
+
[docs-prompts]: https://frontmcp.dev/reference/sdk/prompt 'Prompts'
|
|
141
|
+
[docs-agents]: https://frontmcp.dev/reference/sdk/agent 'Agents'
|
|
142
|
+
[docs-auth]: https://frontmcp.dev/reference/auth/modes 'Authentication'
|
|
143
|
+
[docs-ext-apps]: https://frontmcp.dev/learn/tools-with-a-ui 'Tool UI / MCP Apps'
|
|
144
|
+
[docs-plugins]: https://frontmcp.dev/reference/plugins 'Plugins'
|
|
145
|
+
[docs-testing]: https://frontmcp.dev/reference/testing 'Testing'
|
|
146
|
+
[docs-deploy]: https://frontmcp.dev/reference/deployment/node 'Deployment'
|
|
147
|
+
[docs-production]: https://frontmcp.dev/reference/deployment/production-build 'Production Build'
|
|
@@ -83,7 +83,7 @@ export class RotateSecretsTool extends ToolContext {
|
|
|
83
83
|
| `deployment` | `'serverless'`, `'standalone'`, `'distributed'`, `'browser'` |
|
|
84
84
|
| `provider` | `'bare'`, `'docker'`, `'vercel'`, `'lambda'`, `'cloudflare'`, … |
|
|
85
85
|
| `target` | `'cli'`, `'node'`, `'vercel'`, `'lambda'`, `'cloudflare'`, … (set by `frontmcp build --target`) |
|
|
86
|
-
| `surface` | `'mcp'`, `'cli'`, `'agent'`, `'job'`, `'http-trigger'` — per-call axis
|
|
86
|
+
| `surface` | `'mcp'`, `'cli'`, `'agent'`, `'job'`, `'http-trigger'`, `'webmcp'` — per-call axis |
|
|
87
87
|
| `env` | `'production'`, `'development'`, `'test'` |
|
|
88
88
|
|
|
89
89
|
Multiple axes are AND-ed. Multiple values within an axis are OR-ed.
|
|
@@ -26,15 +26,15 @@ On Linux / Windows servers, this tool simply doesn't exist — it's not in `tool
|
|
|
26
26
|
|
|
27
27
|
## Axes
|
|
28
28
|
|
|
29
|
-
| Axis | Values | Source
|
|
30
|
-
| ------------ | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
31
|
-
| `os` | `'darwin'`, `'linux'`, `'win32'` | `process.platform` (since #417 — was previously `platform`)
|
|
32
|
-
| `runtime` | `'node'`, `'browser'`, `'edge'`, `'bun'`, `'deno'` | Detected at boot
|
|
33
|
-
| `deployment` | `'serverless'`, `'standalone'`, `'distributed'`, `'browser'` | Detected from `frontmcp.config` / env
|
|
34
|
-
| `provider` | `'bare'`, `'docker'`, `'vercel'`, `'lambda'`, `'cloudflare'`, `'netlify'`, `'azure'`, `'gcp'`, `'fly'`, `'render'`, `'railway'` | Auto-detected; override with `FRONTMCP_PROVIDER=<name>`
|
|
35
|
-
| `target` | `'cli'`, `'node'`, `'vercel'`, `'lambda'`, `'cloudflare'`, `'browser'`, `'sdk'`, `'mcpb'`, `'distributed'` | Set by `frontmcp build --target <x
|
|
36
|
-
| `surface` | `'mcp'`, `'cli'`, `'agent'`, `'job'`, `'http-trigger'`
|
|
37
|
-
| `env` | `'production'`, `'development'`, `'test'` | `
|
|
29
|
+
| Axis | Values | Source |
|
|
30
|
+
| ------------ | ------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
31
|
+
| `os` | `'darwin'`, `'linux'`, `'win32'` | `process.platform` (since #417 — was previously `platform`) |
|
|
32
|
+
| `runtime` | `'node'`, `'browser'`, `'edge'`, `'bun'`, `'deno'` | Detected at boot |
|
|
33
|
+
| `deployment` | `'serverless'`, `'standalone'`, `'distributed'`, `'browser'` | Detected from `frontmcp.config` / env |
|
|
34
|
+
| `provider` | `'bare'`, `'docker'`, `'vercel'`, `'lambda'`, `'cloudflare'`, `'netlify'`, `'azure'`, `'gcp'`, `'fly'`, `'render'`, `'railway'` | Auto-detected; override with `FRONTMCP_PROVIDER=<name>` |
|
|
35
|
+
| `target` | `'cli'`, `'node'`, `'vercel'`, `'lambda'`, `'cloudflare'`, `'browser'`, `'sdk'`, `'mcpb'`, `'distributed'` | Set by `frontmcp build --target <x>` in every artifact (`globalThis.FRONTMCP_BUILD_TARGET`; first to run wins, so a `cli` binary loading its server bundle stays `'cli'`); `'unknown'` in dev |
|
|
36
|
+
| `surface` | `'mcp'`, `'cli'`, `'agent'`, `'job'`, `'http-trigger'`, `'webmcp'` | Per-call axis — which entry point is invoking the tool |
|
|
37
|
+
| `env` | `'production'`, `'development'`, `'test'` | `NODE_ENV`, read live (a Worker's `[vars]` beats a bundler's inlined constant) |
|
|
38
38
|
|
|
39
39
|
## Semantics
|
|
40
40
|
|
|
@@ -100,7 +100,7 @@ These are fine for ergonomic branching. For tools that **shouldn't exist at all*
|
|
|
100
100
|
|
|
101
101
|
This is the safest way to expose internal-only tools that you want an agent / job to call but don't want a user to invoke from a chat UI.
|
|
102
102
|
|
|
103
|
-
An MCP client (and the in-process client of a CLI build, surface `'cli'`) never sees such a tool: it is absent from `tools/list`, and `tools/call` answers `Tool "rotate_secrets" not found`, exactly as for a tool that doesn't exist. Resources, resource templates, prompts, agents and skills (including the skills HTTP endpoints, which count as `'mcp'`) follow the same rule, and CodeCall applies its caller's surface to the tools it reaches. An agent's model calls its tools on `'agent'` (and is only offered those its `surface` allows), a job's or workflow step's `this.callTool()` on `'job'`,
|
|
103
|
+
An MCP client (and the in-process client of a CLI build, surface `'cli'`) never sees such a tool: it is absent from `tools/list`, and `tools/call` answers `Tool "rotate_secrets" not found`, exactly as for a tool that doesn't exist. Resources, resource templates, prompts, agents and skills (including the skills HTTP endpoints, which count as `'mcp'`) follow the same rule, and CodeCall applies its caller's surface to the tools it reaches. An agent's model calls its tools on `'agent'` (and is only offered those its `surface` allows), a job's or workflow step's `this.callTool()` on `'job'`, a `@Channel` handling a webhook on `'http-trigger'`, and an in-browser agent calling through WebMCP (`@frontmcp/plugin-webmcp`) on `'webmcp'`. A tool, resource or prompt calling `this.callTool()` is in-process dispatch: that call carries no surface and is not restricted. Code reads its call's surface with `getCallSurface()`. The process-wide axes (`os`, `runtime`, ...) answer `EntryUnavailableError` instead.
|
|
104
104
|
|
|
105
105
|
## See also
|
|
106
106
|
|
|
@@ -39,12 +39,12 @@ That's it. The framework:
|
|
|
39
39
|
|
|
40
40
|
## Template formats
|
|
41
41
|
|
|
42
|
-
| Format | Shape | When
|
|
43
|
-
| ---------------------------- | --------------------------------------- |
|
|
44
|
-
| **FileSource (recommended)** | `{ file: widgetPath }` | `.tsx` / `.jsx` / `.html` source files. Anchor with `import.meta.url`.
|
|
45
|
-
| **Function** | `` (ctx) => ctx.helpers.html`…` `` | Quick demo / one-liner HTML. Annotate `ctx: TemplateContext<In, Out>` ([why](#typescript-gotcha-ts7006)).
|
|
46
|
-
| **HTML / Markdown string** | `'<div>…</div>'` or `'# Title\n- item'` | A string with both `<` and `>` is HTML as written; any other string is Markdown, converted on the server. MDX is **not** compiled.
|
|
47
|
-
| **React component** | `MyWidget` |
|
|
42
|
+
| Format | Shape | When |
|
|
43
|
+
| ---------------------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
|
44
|
+
| **FileSource (recommended)** | `{ file: widgetPath }` | `.tsx` / `.jsx` / `.html` source files. Anchor with `import.meta.url`. |
|
|
45
|
+
| **Function** | `` (ctx) => ctx.helpers.html`…` `` | Quick demo / one-liner HTML. Annotate `ctx: TemplateContext<In, Out>` ([why](#typescript-gotcha-ts7006)). |
|
|
46
|
+
| **HTML / Markdown string** | `'<div>…</div>'` or `'# Title\n- item'` | A string with both `<` and `>` is HTML as written; any other string is Markdown, converted on the server. MDX is **not** compiled. |
|
|
47
|
+
| **React component** | `MyWidget` | Not supported: a bare component reference cannot be bundled, so the page is an empty root. Startup warns once per tool; use `{ file }`. |
|
|
48
48
|
|
|
49
49
|
The renderer auto-detects which one you passed.
|
|
50
50
|
|
|
@@ -74,7 +74,7 @@ Or use the FileSource form — it sidesteps the issue.
|
|
|
74
74
|
| `minHeight` / `maxHeight` | — | `number` (px) or CSS string. Clamp the widget height; auto-resize never reports outside this range. |
|
|
75
75
|
| `aspectRatio` | — | CSS `aspect-ratio` (`'16 / 9'` or `1.5`). Hosts that honor it size by ratio instead of measured height. |
|
|
76
76
|
| `autoResize` | `true` | Report the document height (margins included) to the host after the handshake. Set `false` to opt out (CSS still applies). |
|
|
77
|
-
| `csp` | — | `{ connectDomains?, resourceDomains? }` — emitted on the resource content's `_meta.ui.csp` (#455). Claude honors CSP only here.
|
|
77
|
+
| `csp` | — | `{ connectDomains?, resourceDomains? }` — emitted on the resource content's `_meta.ui.csp` (#455). Claude honors CSP only here. See [CSP origins](#csp-origins). |
|
|
78
78
|
| `contentSecurity` | strict | **No effect yet.** |
|
|
79
79
|
| `escapeStringResults` | unset | `true` escapes plain string results of a template function; `html` / `trustedHtml` stay markup. Default in 1.9. |
|
|
80
80
|
| `widgetAccessible` | `false` | **No effect yet.** |
|
|
@@ -117,9 +117,29 @@ export default function Widget({ output }: { output: { id: string } | null }) {
|
|
|
117
117
|
|
|
118
118
|
- `resources/read ui://widget/{toolName}.html` serves only what was compiled at startup (`static`, the `hybrid` shell), rendered without caller data, or a data-free placeholder that gets the result through the bridge.
|
|
119
119
|
- An `inline` render embeds the call's input and output. It is returned only in that call's `_meta['ui/html']` and is never cached where `resources/read` can serve it, so one caller can't read another caller's widget (GHSA-rhr9-vhpf-jqp7).
|
|
120
|
+
- A page compiled at startup injects no call data (`window.__mcpToolInput` / `window.__mcpToolOutput` are `null`), so the bridge takes the result from the host: `window.openai.toolOutput` (ChatGPT, read at load and followed after) or `ui/notifications/tool-result` (MCP Apps). A `.tsx` widget renders with `loading: true` until it arrives, and `useToolOutput()` returns `null` until then.
|
|
120
121
|
- Hosts that load the widget via `resources/read` (MCP Apps hosts such as Claude) need `servingMode: 'static'` and a template that reads data from `window.FrontMcpBridge`; set `resourceMode: 'inline'` explicitly for Claude in static mode.
|
|
122
|
+
- With the default `servingMode`, every `tools/call` result carries the page in `_meta['ui/html']` — hosts that load the `ui://` resource don't read it, so use `servingMode: 'static'` to leave it out. A call the widget makes back through `ui/callServerTool` gets the data only.
|
|
121
123
|
- The advertised URI percent-encodes the tool name (`app:tool` → `ui://widget/app%3Atool.html`). Encoded and raw forms both read back; a name that decodes to anything outside `A-Z a-z 0-9 _ - . / : @` is rejected.
|
|
122
124
|
|
|
125
|
+
## CSP origins
|
|
126
|
+
|
|
127
|
+
The page FrontMCP writes also carries its own Content-Security-Policy built from `ui.csp`:
|
|
128
|
+
|
|
129
|
+
- An origin must be `https://` or `wss://` (a WebSocket API needs `wss://` in `connectDomains`), a `https://*.` / `wss://*.` wildcard, or `http://` / `ws://` on `localhost` / `127.0.0.1` / `[::1]`.
|
|
130
|
+
- Declared origins are added to what the page already reaches: the CDNs and `resourceDomains` stay in `connect-src`.
|
|
131
|
+
- Any other origin (bare host, `ftp://`, plain `http://` host, a value with a `?query` or `#fragment`) is left out of the page policy; startup logs a warning naming the tool and the origin. The resource `_meta.ui.csp` keeps the origins as written.
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
ui: {
|
|
135
|
+
template: { file: widgetPath },
|
|
136
|
+
csp: {
|
|
137
|
+
connectDomains: ['https://api.example.com', 'wss://live.example.com'],
|
|
138
|
+
resourceDomains: ['https://cdn.example.com'],
|
|
139
|
+
},
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
123
143
|
## Trusted markup and escaping template results
|
|
124
144
|
|
|
125
145
|
Build function-template markup with the `ctx.helpers.html` tagged template. Literal parts stay markup; every interpolated value is HTML-escaped unless it is itself trusted markup:
|
|
@@ -193,7 +213,7 @@ Match the version to `@frontmcp/sdk`. Without it, server-side bundling fails wit
|
|
|
193
213
|
npm install esbuild # in "dependencies", not "devDependencies"
|
|
194
214
|
```
|
|
195
215
|
|
|
196
|
-
Projects created with `frontmcp create` already have it through the `frontmcp` package. `@frontmcp/uipack` declares it as an optional peer dependency (`>=0.27.0 <1`). Without it, the call fails with an error naming the widget.
|
|
216
|
+
Projects created with `frontmcp create` already have it through the `frontmcp` package. `@frontmcp/uipack` declares it as an optional peer dependency (`>=0.27.0 <1`). Without it, the call fails with an error naming the widget. Bundling works the same in CommonJS and ES-module (`"type": "module"`) projects.
|
|
197
217
|
|
|
198
218
|
## Widget bridge — `window.FrontMcpBridge`
|
|
199
219
|
|
|
@@ -244,6 +264,8 @@ The page follows the host theme. When an MCP Apps host sends `theme: 'light' | '
|
|
|
244
264
|
| **MCP Inspector** | Useful for local development. Static mode works fine. |
|
|
245
265
|
| **Gemini / unknown** | `ui` is ignored — JSON output is returned. |
|
|
246
266
|
|
|
267
|
+
The host is decided when the client connects: a `transport.platformDetection.mappings` entry matching the client name wins; then a client that declares the MCP Apps extension (`io.modelcontextprotocol/ui`) is `ext-apps` whatever its name (`gemini-cli` included); then the client name. Opt a client out of MCP Apps with a mapping: `platformDetection: { mappings: [{ pattern: 'gemini-cli', platform: 'gemini' }] }`.
|
|
268
|
+
|
|
247
269
|
## Widget sizing
|
|
248
270
|
|
|
249
271
|
Set sizing in the `ui` config — no hand-rolled `ui/notifications/size-changed` + `ResizeObserver` needed:
|
|
@@ -287,6 +287,11 @@ authorities: {
|
|
|
287
287
|
}
|
|
288
288
|
```
|
|
289
289
|
|
|
290
|
+
Tools, resources, agents and jobs (workflow steps included) run the pipes when their context is built, before any hook
|
|
291
|
+
or `execute()` reads `this.auth`, so `this.auth.tenantId` is set there. Pipes can be async; one that throws is logged
|
|
292
|
+
and leaves its fields `undefined`. Pipes extend `this.auth` only -- authority policies still evaluate the claims from
|
|
293
|
+
`claimsMapping` / `claimsResolver`. Up to 1.8.7 `pipes` never ran (their fields were always `undefined`).
|
|
294
|
+
|
|
290
295
|
### Skill Authorities (`@Skill({ authorities })`)
|
|
291
296
|
|
|
292
297
|
`authorities` on `@Skill` is enforced exactly like the other entry types, across
|
|
@@ -75,13 +75,13 @@ Build push-based notification channels that stream real-time events into Claude
|
|
|
75
75
|
|
|
76
76
|
## Common Patterns
|
|
77
77
|
|
|
78
|
-
| Pattern | Correct
|
|
79
|
-
| -------------- |
|
|
80
|
-
| Meta keys | `meta: { env: 'prod' }`
|
|
81
|
-
| Source naming | `name: 'deploy-alerts'`
|
|
82
|
-
| Two-way gating | Check sender identity before emitting
|
|
83
|
-
| Error channels | Use `app-event` source with event bus
|
|
84
|
-
| Manual push |
|
|
78
|
+
| Pattern | Correct | Incorrect | Why |
|
|
79
|
+
| -------------- | ------------------------------------------ | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
|
80
|
+
| Meta keys | `meta: { env: 'prod' }` | `meta: { 'my-env': 'prod' }` | Meta keys must be valid identifiers (letters, digits, underscores) |
|
|
81
|
+
| Source naming | `name: 'deploy-alerts'` | `name: 'Deploy Alerts!'` | Channel names should be kebab-case identifiers |
|
|
82
|
+
| Two-way gating | Check sender identity before emitting | Trust room/group membership | Prevent prompt injection from untrusted group members |
|
|
83
|
+
| Error channels | Use `app-event` source with event bus | Poll for errors in a loop | Event bus is push-based and efficient |
|
|
84
|
+
| Manual push | `await scope.channelNotifications?.send()` | `sendToSubscribedSessions()` for a regular push | `send()` runs the hookable `channels:send-notification` flow (defaultMeta, channel meta, hooks); the `sendTo*` methods deliver directly |
|
|
85
85
|
|
|
86
86
|
## Verification Checklist
|
|
87
87
|
|
|
@@ -102,24 +102,25 @@ Build push-based notification channels that stream real-time events into Claude
|
|
|
102
102
|
|
|
103
103
|
- [ ] `twoWay: true` is set on channels that need replies
|
|
104
104
|
- [ ] `channel-reply` tool appears in tool list
|
|
105
|
-
- [ ] `onReply()` is implemented and forwards to external system
|
|
105
|
+
- [ ] `onReply()` is implemented and forwards to external system (if it throws, `channel-reply` answers an error result)
|
|
106
106
|
- [ ] Sender authentication is enforced before emitting events
|
|
107
107
|
|
|
108
108
|
### Sources
|
|
109
109
|
|
|
110
110
|
- [ ] Webhook endpoints return 200 on success
|
|
111
|
-
- [ ] Event bus subscriptions are cleaned up on scope teardown
|
|
111
|
+
- [ ] Event bus subscriptions are cleaned up on scope teardown, and service channels get `onDisconnect()` on shutdown and on `dispose()`
|
|
112
112
|
- [ ] Agent/job completion filters match expected IDs
|
|
113
113
|
|
|
114
114
|
## Troubleshooting
|
|
115
115
|
|
|
116
|
-
| Problem | Cause
|
|
117
|
-
| ---------------------------- |
|
|
118
|
-
| No notifications arrive | Client doesn't support channels
|
|
119
|
-
| `channel-reply` tool missing | No two-way channels registered
|
|
120
|
-
| Webhook returns 500 | `onEvent()` throws
|
|
121
|
-
|
|
|
122
|
-
|
|
|
116
|
+
| Problem | Cause | Solution |
|
|
117
|
+
| ---------------------------- | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
|
|
118
|
+
| No notifications arrive | Client doesn't support channels | Check client capabilities include `experimental['claude/channel']` |
|
|
119
|
+
| `channel-reply` tool missing | No two-way channels registered | Set `twoWay: true` on at least one channel |
|
|
120
|
+
| Webhook returns 500 | `onEvent()` throws | Check channel handler error logs |
|
|
121
|
+
| A notification never arrives | A `ChannelSendHook` stopped it, or `ChannelListHook` left the channel out of the session's subscriptions | Check plugins hooking `channels:send-notification` / `channels:list` |
|
|
122
|
+
| Duplicate notifications | Multiple sessions subscribed | This is correct behavior -- each session gets its own copy |
|
|
123
|
+
| Events lost on reconnect | Channels are in-memory | Channel state resets on server restart; use persistent sources |
|
|
123
124
|
|
|
124
125
|
## Examples
|
|
125
126
|
|
|
@@ -59,8 +59,8 @@ class ErrorAlertChannel extends ChannelContext {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
// In your application code:
|
|
63
|
-
scope.channelEventBus
|
|
62
|
+
// In your application code (in a tool: this.scope.channelEventBus):
|
|
63
|
+
scope.channelEventBus?.emit('app:error', {
|
|
64
64
|
message: 'Connection refused',
|
|
65
65
|
stack: 'Error: ECONNREFUSED...',
|
|
66
66
|
level: 'critical',
|
|
@@ -181,7 +181,7 @@ class LogWatcherChannel extends ChannelContext {
|
|
|
181
181
|
|
|
182
182
|
## Manual Source
|
|
183
183
|
|
|
184
|
-
No automatic wiring. Push notifications programmatically via `scope.channelNotifications.send()
|
|
184
|
+
No automatic wiring. Push notifications programmatically via `scope.channelNotifications.send()`, which runs the hookable `channels:send-notification` flow like every channel notification: `channels.defaultMeta`, then the channel's `meta`, then the notification's own meta, with `source` set to the channel name.
|
|
185
185
|
|
|
186
186
|
```typescript
|
|
187
187
|
const StatusChannel = channel({
|
|
@@ -193,7 +193,7 @@ const StatusChannel = channel({
|
|
|
193
193
|
}));
|
|
194
194
|
|
|
195
195
|
// Push from anywhere with scope access:
|
|
196
|
-
scope.channelNotifications
|
|
196
|
+
await scope.channelNotifications?.send('status-updates', 'Server maintenance starting in 5 minutes');
|
|
197
197
|
```
|
|
198
198
|
|
|
199
199
|
## Replay Buffer
|
|
@@ -13,7 +13,7 @@ Two-way channels let external users communicate with Claude Code through messagi
|
|
|
13
13
|
2. **Transform**: `onEvent()` converts to `ChannelNotification`
|
|
14
14
|
3. **Push**: Notification sent to Claude Code session
|
|
15
15
|
4. **Reply**: Claude calls `channel-reply` tool with response text
|
|
16
|
-
5. **Forward**: `onReply()` sends the reply back to the external platform
|
|
16
|
+
5. **Forward**: `onReply()` sends the reply back to the external platform. If it throws, `channel-reply` answers an error result with the message, so Claude knows the reply did not go out (up to 1.8.7 the tool reported success)
|
|
17
17
|
|
|
18
18
|
## API Surface
|
|
19
19
|
|
package/catalog/frontmcp-config/examples/configure-deployment-targets/distributed-ha-config.md
CHANGED
|
@@ -70,6 +70,8 @@ frontmcp build --target node
|
|
|
70
70
|
FRONTMCP_DEPLOYMENT_MODE=distributed frontmcp build --target distributed
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
The distributed build writes the `ha` block to `FRONTMCP_HA_HEARTBEAT_INTERVAL_MS`, `FRONTMCP_HA_HEARTBEAT_TTL_MS`, `FRONTMCP_HA_TAKEOVER_GRACE_MS` and `FRONTMCP_HA_KEY_PREFIX` in the generated setup file (only where the platform has not set them); each pod reads them at startup. Give every pod the same `MCP_SESSION_SECRET` so any pod can route a session's request to the pod that owns it.
|
|
74
|
+
|
|
73
75
|
### Server Code
|
|
74
76
|
|
|
75
77
|
```typescript
|
|
@@ -19,7 +19,7 @@ Configure Vercel KV for session storage in serverless Vercel deployments.
|
|
|
19
19
|
|
|
20
20
|
```typescript
|
|
21
21
|
// src/server.ts
|
|
22
|
-
import {
|
|
22
|
+
import { App, FrontMcp } from '@frontmcp/sdk';
|
|
23
23
|
|
|
24
24
|
@App({ name: 'my-app' })
|
|
25
25
|
class MyApp {}
|
|
@@ -33,7 +33,6 @@ class MyApp {}
|
|
|
33
33
|
},
|
|
34
34
|
transport: {
|
|
35
35
|
protocol: 'stateless-api',
|
|
36
|
-
sessionMode: 'stateless',
|
|
37
36
|
},
|
|
38
37
|
})
|
|
39
38
|
class Server {}
|