@frontmcp/skills 1.5.0-rc.1 → 1.5.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.
|
@@ -257,7 +257,7 @@ The full `@Tool({...})` surface — including the former `create-tool-annotation
|
|
|
257
257
|
| [`basic-openapi-adapter`](./examples/openapi-adapter/basic-openapi-adapter.md) | Basic | Demonstrates converting an OpenAPI specification into MCP tools automatically using `OpenapiAdapter` with minimal configuration. |
|
|
258
258
|
| [`authenticated-adapter-with-polling`](./examples/openapi-adapter/authenticated-adapter-with-polling.md) | Intermediate | Demonstrates configuring authentication (API key and bearer token) and automatic spec polling for OpenAPI adapters. |
|
|
259
259
|
| [`format-resolution-and-custom-resolvers`](./examples/openapi-adapter/format-resolution-and-custom-resolvers.md) | Intermediate | Demonstrates using built-in and custom format resolvers to enrich tool input schemas with concrete constraints from OpenAPI format values. |
|
|
260
|
-
| [`ref-security-and-filtering`](./examples/openapi-adapter/ref-security-and-filtering.md) | Intermediate | Demonstrates configuring $ref resolution security to prevent SSRF attacks and filtering which API operations become MCP tools. |
|
|
260
|
+
| [`ref-security-and-filtering`](./examples/openapi-adapter/ref-security-and-filtering.md) | Intermediate | Demonstrates configuring $ref / spec-URL resolution security to prevent SSRF attacks (GHSA-65h7-9wrw-629c) and filtering which API operations become MCP tools. |
|
|
261
261
|
| [`multi-api-hub-with-inline-spec`](./examples/openapi-adapter/multi-api-hub-with-inline-spec.md) | Advanced | Demonstrates registering multiple OpenAPI adapters from different APIs in a single app, including one with an inline spec definition instead of a remote URL. |
|
|
262
262
|
|
|
263
263
|
### `official-plugins`
|
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
name: ref-security-and-filtering
|
|
3
3
|
reference: openapi-adapter
|
|
4
4
|
level: intermediate
|
|
5
|
-
description: 'Demonstrates configuring $ref resolution security to prevent SSRF attacks and filtering which API operations become MCP tools.'
|
|
5
|
+
description: 'Demonstrates configuring $ref / spec-URL resolution security to prevent SSRF attacks (GHSA-65h7-9wrw-629c) and filtering which API operations become MCP tools.'
|
|
6
6
|
tags: [development, openapi, adapters, security, ssrf, filtering]
|
|
7
7
|
features:
|
|
8
|
-
- '
|
|
9
|
-
- '
|
|
10
|
-
- 'Using `
|
|
8
|
+
- 'Secure defaults: external `$ref` resolution off, spec-URL redirects not followed, internal/private targets blocked (DNS-resolved) — on `mcp-from-openapi` >= 2.5.0'
|
|
9
|
+
- 'Opting back into external refs with `allowedProtocols`, and restricting the spec URL + `$ref`s with `allowedHosts`'
|
|
10
|
+
- 'Using `allowInternalIPs` for trusted internal/local targets (governs the spec URL and `$ref`s)'
|
|
11
11
|
- 'Filtering operations with `includeOperations`, `excludeOperations`, and `filterFn`'
|
|
12
12
|
- 'Combining security hardening with operation filtering for a production-ready setup'
|
|
13
13
|
---
|
|
14
14
|
|
|
15
15
|
# $ref Security and Operation Filtering
|
|
16
16
|
|
|
17
|
-
Demonstrates configuring $ref resolution security to prevent SSRF attacks and filtering which API operations become MCP tools.
|
|
17
|
+
Demonstrates configuring $ref / spec-URL resolution security to prevent SSRF attacks (GHSA-65h7-9wrw-629c) and filtering which API operations become MCP tools.
|
|
18
18
|
|
|
19
19
|
## Code
|
|
20
20
|
|
|
@@ -26,14 +26,19 @@ import { OpenapiAdapter } from '@frontmcp/adapters';
|
|
|
26
26
|
@App({
|
|
27
27
|
name: 'secure-app',
|
|
28
28
|
adapters: [
|
|
29
|
-
// Production-hardened:
|
|
29
|
+
// Production-hardened: ENABLE external $refs but restrict to trusted hosts.
|
|
30
|
+
// (External refs are OFF by default in FrontMCP; you must opt in.)
|
|
31
|
+
// NOTE: allowedHosts now also gates the spec URL itself, so the spec host
|
|
32
|
+
// (api.partner.com) must be in the list. Internal targets stay blocked and
|
|
33
|
+
// hostnames are DNS-resolved (mcp-from-openapi >= 2.5.0).
|
|
30
34
|
OpenapiAdapter.init({
|
|
31
35
|
name: 'partner-api',
|
|
32
36
|
url: 'https://api.partner.com/openapi.json',
|
|
33
37
|
baseUrl: 'https://api.partner.com',
|
|
34
38
|
loadOptions: {
|
|
35
39
|
refResolution: {
|
|
36
|
-
|
|
40
|
+
allowedProtocols: ['http', 'https'], // opt back into external refs
|
|
41
|
+
// Only allow the spec URL + $refs pointing to the partner's own hosts
|
|
37
42
|
allowedHosts: ['schemas.partner.com', 'api.partner.com'],
|
|
38
43
|
// Block additional hosts known to be problematic
|
|
39
44
|
blockedHosts: ['internal.partner.com'],
|
|
@@ -50,7 +55,8 @@ import { OpenapiAdapter } from '@frontmcp/adapters';
|
|
|
50
55
|
},
|
|
51
56
|
}),
|
|
52
57
|
|
|
53
|
-
// Internal API: allow internal
|
|
58
|
+
// Internal API: allow internal targets (trusted environment only).
|
|
59
|
+
// allowInternalIPs re-allows BOTH the spec-URL fetch to 10.0.0.5 AND $refs.
|
|
54
60
|
OpenapiAdapter.init({
|
|
55
61
|
name: 'internal-api',
|
|
56
62
|
url: 'http://10.0.0.5:8080/openapi.json',
|
|
@@ -67,7 +73,8 @@ import { OpenapiAdapter } from '@frontmcp/adapters';
|
|
|
67
73
|
},
|
|
68
74
|
}),
|
|
69
75
|
|
|
70
|
-
// Maximum lockdown: no external $refs at all
|
|
76
|
+
// Maximum lockdown: no external $refs at all. This matches the FrontMCP
|
|
77
|
+
// default (external refs off) — shown explicitly for clarity.
|
|
71
78
|
OpenapiAdapter.init({
|
|
72
79
|
name: 'sandbox-api',
|
|
73
80
|
url: 'https://sandbox.example.com/openapi.json',
|
|
@@ -99,9 +106,9 @@ class MyServer {}
|
|
|
99
106
|
|
|
100
107
|
## What This Demonstrates
|
|
101
108
|
|
|
102
|
-
-
|
|
103
|
-
-
|
|
104
|
-
- Using `
|
|
109
|
+
- Secure defaults: external `$ref` resolution off, spec-URL redirects not followed, internal/private targets blocked (DNS-resolved) — on `mcp-from-openapi` >= 2.5.0
|
|
110
|
+
- Opting back into external refs with `allowedProtocols`, and restricting the spec URL + `$ref`s with `allowedHosts`
|
|
111
|
+
- Using `allowInternalIPs` for trusted internal/local targets (governs the spec URL and `$ref`s)
|
|
105
112
|
- Filtering operations with `includeOperations`, `excludeOperations`, and `filterFn`
|
|
106
113
|
- Combining security hardening with operation filtering for a production-ready setup
|
|
107
114
|
|
|
@@ -285,68 +285,79 @@ OpenapiAdapter.init({
|
|
|
285
285
|
| `resolveFormats` | `boolean` | `false` | Enable built-in format resolvers (uuid, date-time, email, int32, etc.) |
|
|
286
286
|
| `formatResolvers` | `Record<string, FormatResolver>` | `undefined` | Custom resolvers; merged with built-ins when `resolveFormats: true`, custom takes precedence |
|
|
287
287
|
|
|
288
|
-
## $ref Resolution Security
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
288
|
+
## Spec Loading & $ref Resolution Security (SSRF)
|
|
289
|
+
|
|
290
|
+
> **Advisories: GHSA-v6ph-xcq9-qxxj, GHSA-65h7-9wrw-629c.** Loading a spec fetches
|
|
291
|
+
> attacker-influenceable URLs (the spec `url` and any external `$ref`s) — an SSRF
|
|
292
|
+
> vector. Hostname-string denylists are bypassable via DNS names that resolve to
|
|
293
|
+
> internal IPs (e.g. `http://127.0.0.1.nip.io/`), redirects, and IPv4-mapped IPv6.
|
|
294
|
+
> **Use `mcp-from-openapi` ≥ 2.5.0**, which resolves DNS and validates the
|
|
295
|
+
> *resolved IP*, guards the spec-URL fetch (not just `$ref`s), and re-validates
|
|
296
|
+
> every redirect hop.
|
|
297
|
+
|
|
298
|
+
FrontMCP's secure defaults:
|
|
299
|
+
|
|
300
|
+
- **External `$ref` resolution is disabled by default** — only internal `#/...`
|
|
301
|
+
refs resolve; inline `spec:` is unaffected. Enable by setting
|
|
302
|
+
`loadOptions.refResolution` explicitly.
|
|
303
|
+
- **Spec-URL redirects are not followed by default** — opt in with
|
|
304
|
+
`loadOptions.followRedirects: true` (each hop is still re-validated).
|
|
305
|
+
- **Internal/private targets are blocked** for the spec `url` and `$ref`s alike
|
|
306
|
+
(loopback, RFC 1918, CGNAT, link-local/cloud-metadata `169.254/16`, multicast,
|
|
307
|
+
IPv6 ULA/link-local), and hostnames are **DNS-resolved** and re-checked.
|
|
308
|
+
- **`file://` is blocked** (prevents local file reads).
|
|
309
|
+
|
|
310
|
+
Configure via `loadOptions.refResolution` (applies to the spec URL **and** `$ref`s):
|
|
297
311
|
|
|
298
312
|
```typescript
|
|
299
|
-
//
|
|
313
|
+
// DEFAULT: external $refs disabled, redirects not followed, internal targets blocked.
|
|
314
|
+
// (No config needed; shown for clarity.)
|
|
300
315
|
OpenapiAdapter.init({
|
|
301
316
|
name: 'my-api',
|
|
302
317
|
url: 'https://api.example.com/openapi.json',
|
|
303
318
|
loadOptions: {
|
|
304
|
-
refResolution: {
|
|
305
|
-
allowedHosts: ['schemas.example.com'],
|
|
306
|
-
},
|
|
319
|
+
refResolution: { allowedProtocols: [] },
|
|
307
320
|
},
|
|
308
321
|
});
|
|
309
322
|
|
|
310
|
-
//
|
|
323
|
+
// Enable external $refs (public hosts only; internal targets stay blocked, DNS-validated)
|
|
311
324
|
OpenapiAdapter.init({
|
|
312
325
|
name: 'my-api',
|
|
313
326
|
url: 'https://api.example.com/openapi.json',
|
|
314
327
|
loadOptions: {
|
|
315
|
-
refResolution: {
|
|
316
|
-
allowedProtocols: ['http', 'https', 'file'],
|
|
317
|
-
},
|
|
328
|
+
refResolution: { allowedProtocols: ['http', 'https'] },
|
|
318
329
|
},
|
|
319
330
|
});
|
|
320
331
|
|
|
321
|
-
//
|
|
332
|
+
// Restrict the spec URL / $refs to specific hosts only
|
|
322
333
|
OpenapiAdapter.init({
|
|
323
|
-
name: '
|
|
324
|
-
url: '
|
|
334
|
+
name: 'my-api',
|
|
335
|
+
url: 'https://api.example.com/openapi.json',
|
|
325
336
|
loadOptions: {
|
|
326
|
-
refResolution: {
|
|
327
|
-
allowInternalIPs: true,
|
|
328
|
-
},
|
|
337
|
+
refResolution: { allowedProtocols: ['http', 'https'], allowedHosts: ['schemas.example.com'] },
|
|
329
338
|
},
|
|
330
339
|
});
|
|
331
340
|
|
|
332
|
-
//
|
|
341
|
+
// Local / internal development: allow loopback/private targets for the spec URL AND $refs
|
|
333
342
|
OpenapiAdapter.init({
|
|
334
|
-
name: '
|
|
335
|
-
url: '
|
|
343
|
+
name: 'local-api',
|
|
344
|
+
url: 'http://localhost:3000/openapi.json',
|
|
336
345
|
loadOptions: {
|
|
337
|
-
refResolution: {
|
|
338
|
-
allowedProtocols: [],
|
|
339
|
-
},
|
|
346
|
+
refResolution: { allowInternalIPs: true },
|
|
340
347
|
},
|
|
341
348
|
});
|
|
342
349
|
```
|
|
343
350
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
|
347
|
-
|
|
|
348
|
-
| `
|
|
349
|
-
| `
|
|
351
|
+
These apply to **both** the spec-URL fetch and external `$ref` resolution (`mcp-from-openapi` ≥ 2.5.0):
|
|
352
|
+
|
|
353
|
+
| Option | Type | Default (FrontMCP) | Description |
|
|
354
|
+
| ------------------ | ---------- | ------------------ | -------------------------------------------------------------------------------------------------- |
|
|
355
|
+
| `allowedProtocols` | `string[]` | `[]` | Protocols allowed for external `$ref` resolution. **FrontMCP defaults to `[]`** (external refs off); set `['http','https']` to enable |
|
|
356
|
+
| `allowedHosts` | `string[]` | `undefined` | When set, only the spec URL / `$ref` URLs to these hostnames are allowed |
|
|
357
|
+
| `blockedHosts` | `string[]` | `undefined` | Additional hostnames/IPs to block beyond the built-in internal-address list |
|
|
358
|
+
| `allowInternalIPs` | `boolean` | `false` | Allow loopback/private/internal targets for the spec URL **and** `$ref`s (skips ranges + DNS recheck). Trusted/local only |
|
|
359
|
+
|
|
360
|
+
> `followRedirects` (a `loadOptions` field, not `refResolution`) defaults to `false` in FrontMCP.
|
|
350
361
|
|
|
351
362
|
## Load Options
|
|
352
363
|
|
|
@@ -375,7 +386,7 @@ OpenapiAdapter.init({
|
|
|
375
386
|
| Auth configuration | `staticAuth: { jwt: process.env.API_TOKEN! }` | Hardcoding secrets: `staticAuth: { jwt: 'sk-xxx' }` | Always use environment variables |
|
|
376
387
|
| Spec source | Use `url` for hosted specs or `spec` for inline | Using both `url` and `spec` simultaneously | Only one source; `spec` takes precedence |
|
|
377
388
|
| Multiple APIs | Separate `OpenapiAdapter.init()` with unique `name` values | Same `name` for different adapters | Duplicate names cause tool collisions |
|
|
378
|
-
|
|
|
389
|
+
| Spec/$ref SSRF | Keep secure defaults (external refs off, redirects off, internal targets blocked) on `mcp-from-openapi` ≥ 2.5.0 | Setting `allowInternalIPs: true` in production; forwarding untrusted spec URLs without an `allowedHosts` allow-list | Defaults protect against SSRF (incl. DNS-name-to-internal) |
|
|
379
390
|
| Format resolution | `generateOptions: { resolveFormats: true }` | Writing manual patterns for standard formats | Built-in resolvers handle uuid, date-time, etc. |
|
|
380
391
|
|
|
381
392
|
## Verification Checklist
|
|
@@ -409,8 +420,9 @@ OpenapiAdapter.init({
|
|
|
409
420
|
| Authentication errors on API calls | Wrong auth config or missing credentials | Configure `staticAuth`, `securityResolver`, `authProviderMapper`, or `additionalHeaders`; verify env vars |
|
|
410
421
|
| Duplicate tool name error | Two adapters with the same `name` | Give each adapter a unique `name` |
|
|
411
422
|
| Stale tools after API update | Spec polling not configured | Add `polling: { intervalMs: 300000 }` |
|
|
412
|
-
| External $refs not resolving |
|
|
413
|
-
|
|
|
423
|
+
| External $refs not resolving | External refs are **disabled by default** in FrontMCP | Set `loadOptions.refResolution.allowedProtocols: ['http','https']` (add `allowedHosts` to restrict) |
|
|
424
|
+
| Spec URL / $ref to internal host blocked | Target is loopback/private, or a DNS name resolving to one (SSRF guard) | Use `refResolution.allowInternalIPs: true` only in trusted/local environments |
|
|
425
|
+
| Spec URL redirect not followed | `followRedirects` defaults to `false` | Set `loadOptions.followRedirects: true` (each hop is re-validated on `mcp-from-openapi` ≥ 2.5.0) |
|
|
414
426
|
| TypeScript error importing adapter | Wrong import path | Import from `@frontmcp/adapters` |
|
|
415
427
|
|
|
416
428
|
## Examples
|
|
@@ -420,7 +432,7 @@ OpenapiAdapter.init({
|
|
|
420
432
|
| [`basic-openapi-adapter`](../examples/openapi-adapter/basic-openapi-adapter.md) | Basic | Demonstrates converting an OpenAPI specification into MCP tools automatically using `OpenapiAdapter` with minimal configuration. |
|
|
421
433
|
| [`authenticated-adapter-with-polling`](../examples/openapi-adapter/authenticated-adapter-with-polling.md) | Intermediate | Demonstrates configuring authentication (API key and bearer token) and automatic spec polling for OpenAPI adapters. |
|
|
422
434
|
| [`format-resolution-and-custom-resolvers`](../examples/openapi-adapter/format-resolution-and-custom-resolvers.md) | Intermediate | Demonstrates using built-in and custom format resolvers to enrich tool input schemas with concrete constraints from OpenAPI format values. |
|
|
423
|
-
| [`ref-security-and-filtering`](../examples/openapi-adapter/ref-security-and-filtering.md) | Intermediate | Demonstrates configuring $ref resolution security to prevent SSRF attacks and filtering which API operations become MCP tools. |
|
|
435
|
+
| [`ref-security-and-filtering`](../examples/openapi-adapter/ref-security-and-filtering.md) | Intermediate | Demonstrates configuring $ref / spec-URL resolution security to prevent SSRF attacks (GHSA-65h7-9wrw-629c) and filtering which API operations become MCP tools. |
|
|
424
436
|
| [`multi-api-hub-with-inline-spec`](../examples/openapi-adapter/multi-api-hub-with-inline-spec.md) | Advanced | Demonstrates registering multiple OpenAPI adapters from different APIs in a single app, including one with an inline spec definition instead of a remote URL. |
|
|
425
437
|
|
|
426
438
|
> See all examples in [`examples/openapi-adapter/`](../examples/openapi-adapter/)
|
|
@@ -2143,13 +2143,13 @@
|
|
|
2143
2143
|
},
|
|
2144
2144
|
{
|
|
2145
2145
|
"name": "ref-security-and-filtering",
|
|
2146
|
-
"description": "Demonstrates configuring $ref resolution security to prevent SSRF attacks and filtering which API operations become MCP tools.",
|
|
2146
|
+
"description": "Demonstrates configuring $ref / spec-URL resolution security to prevent SSRF attacks (GHSA-65h7-9wrw-629c) and filtering which API operations become MCP tools.",
|
|
2147
2147
|
"level": "intermediate",
|
|
2148
2148
|
"tags": ["development", "openapi", "adapters", "security", "ssrf", "filtering"],
|
|
2149
2149
|
"features": [
|
|
2150
|
-
"
|
|
2151
|
-
"
|
|
2152
|
-
"Using `
|
|
2150
|
+
"Secure defaults: external `$ref` resolution off, spec-URL redirects not followed, internal/private targets blocked (DNS-resolved) — on `mcp-from-openapi` >= 2.5.0",
|
|
2151
|
+
"Opting back into external refs with `allowedProtocols`, and restricting the spec URL + `$ref`s with `allowedHosts`",
|
|
2152
|
+
"Using `allowInternalIPs` for trusted internal/local targets (governs the spec URL and `$ref`s)",
|
|
2153
2153
|
"Filtering operations with `includeOperations`, `excludeOperations`, and `filterFn`",
|
|
2154
2154
|
"Combining security hardening with operation filtering for a production-ready setup"
|
|
2155
2155
|
]
|