fix(mcp): support draft-2020-12 tool schemas (wire in Firecrawl)#25
Merged
Conversation
Firecrawl's v2 MCP tools declare their input schema as JSON Schema draft
2020-12. Mastra's tool-input validator can't resolve that meta-schema and
rejects every call locally ("no schema with key or ref .../2020-12/schema"),
so the tools connect but never actually run.
- Override the input schema of the firecrawl scrape/search tools with clean
Zod schemas, mutating the Tool instance in place (its execute() validates
against this.inputSchema at call time and is lexically bound to the
instance, so a spread copy never takes effect).
- Apply expandEnvVars to HTTP MCP server urls so the firecrawl key can live
in .env (${FIRECRAWL_MCP_URL}) instead of the git-tracked yaml.
- Register firecrawl in mcp-servers.yaml, whitelisted to scrape + search.
Verified end-to-end: firecrawl_scrape returns real page markdown.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The workspace only has the VerdictNo blockers, but a few real risks around secret-in-URL logging, opaque failure on a missing env var, and an in-place mutation that's untested and brittle. Warnings
Nits
|
…tests
- Guard HTTP MCP urls: throw a clear "empty url; is its env var set?" error
instead of an opaque "Invalid URL" when ${FIRECRAWL_MCP_URL} is unset.
- Extract the draft-2020-12 schema override into applySchemaOverrides(), which
warns when an override's server is loaded but the tool id is missing (e.g. a
Firecrawl rename) instead of silently regressing to validation failures.
- Add mcp-client.test.ts pinning the load-bearing behaviors: in-place mutation
(same reference), the rename warning, no-warn when the server is absent, and
that the real SCHEMA_OVERRIDES are valid Zod schemas.
Reviewer's secret-in-URL note: confirmed mcp-client logs only server/tool names,
never the resolved url. YAML-indent nit: brave and firecrawl blocks already use
matching 7-space child indentation; no change.
Verified: unit tests pass, lint clean, firecrawl_scrape still scrapes end-to-end.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The CI typecheck (tsc --noEmit, not run by the lint-only pre-commit hook)
flagged toBe(zodSchema) against an inferred { $schema: string }. Type the
fake tool's inputSchema as unknown — mirroring the real Tool, whose schema
is replaced from a JSON-schema object to a Zod schema.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Firecrawl's v2 MCP tools declare their input schema as JSON Schema draft 2020-12. Mastra's tool-input validator can't resolve that meta-schema, so it rejects every call locally before it leaves the machine:
The tools connect and appear in the agent's toolset, but every call fails. (brave-search is unaffected — its schema is draft-07.)
Fix
scrape,search) with clean Zod schemas. The override mutates theToolinstance in place rather than spreading a copy:Tool.executevalidates againstthis.inputSchemaat call time and is an arrow function lexically bound to the instance, so a spread copy never takes effect (found this the hard way — validation passed but execute still failed until the mutation).expandEnvVarsnow applies to HTTP MCP serverurls, so the Firecrawl key lives in.envas${FIRECRAWL_MCP_URL}instead of being hardcoded in the git-trackedmcp-servers.yaml.mcp-servers.yaml, whitelisted toscrape+search.Setup
Consumers add to
.env:and opt an agent in via its
mcpServers: [firecrawl]setting.Verification
Probed the real code path (
initMCPClient→getMCPTools→ toolexecute):firecrawl_scrapeonhttps://example.comreturns real page markdown end-to-end, no validation error.🤖 Generated with Claude Code