Skip to content

fix(mcp): support draft-2020-12 tool schemas (wire in Firecrawl)#25

Merged
AvivK5498 merged 3 commits into
mainfrom
fix/mcp-draft-2020-12-schema
Jun 22, 2026
Merged

fix(mcp): support draft-2020-12 tool schemas (wire in Firecrawl)#25
AvivK5498 merged 3 commits into
mainfrom
fix/mcp-draft-2020-12-schema

Conversation

@AvivK5498

Copy link
Copy Markdown
Owner

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:

Tool input validation failed for firecrawl_firecrawl_scrape.
- root: Schema validation error: no schema with key or ref "https://json-schema.org/draft/2020-12/schema"

The tools connect and appear in the agent's toolset, but every call fails. (brave-search is unaffected — its schema is draft-07.)

Fix

  • Schema override — replace the input schema of the two whitelisted firecrawl tools (scrape, search) with clean Zod schemas. The override mutates the Tool instance in place rather than spreading a copy: Tool.execute validates against this.inputSchema at 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).
  • Env-var MCP urlsexpandEnvVars now applies to HTTP MCP server urls, so the Firecrawl key lives in .env as ${FIRECRAWL_MCP_URL} instead of being hardcoded in the git-tracked mcp-servers.yaml.
  • Register firecrawl in mcp-servers.yaml, whitelisted to scrape + search.

Setup

Consumers add to .env:

FIRECRAWL_MCP_URL=https://mcp.firecrawl.dev/<your-key>/v2/mcp

and opt an agent in via its mcpServers: [firecrawl] setting.

Verification

Probed the real code path (initMCPClientgetMCPTools → tool execute): firecrawl_scrape on https://example.com returns real page markdown end-to-end, no validation error.

🤖 Generated with Claude Code

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>
@AvivK5498 AvivK5498 added the review-me Automated PR Review with Eve label Jun 22, 2026
@ak-prbot

ak-prbot Bot commented Jun 22, 2026

Copy link
Copy Markdown

The workspace only has the skills/ dir mounted; the repo files aren't accessible, so I'm reviewing from the diff in context.

Verdict

No 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

  • src/agent/mcp-client.ts:87new URL(expandEnvVars(cfg.url)) will throw (or silently produce a broken URL) if FIRECRAWL_MCP_URL is unset, and the error surfaces at MCP init rather than pointing at the missing var — guard with an explicit check that throws a clear "FIRECRAWL_MCP_URL not set" message.
  • src/agent/mcp-client.ts:87 — the Firecrawl API key is embedded in the URL; if the MCPClient config or logger ever prints url, the key leaks into logs — confirm nothing downstream logs the resolved URL, or strip/redact it before passing to the client.
  • src/agent/mcp-client.ts:158 — the in-place mutation (tool as { inputSchema?: unknown }).inputSchema = ... is a load-bearing workaround with no test and a hardcoded comment about Mastra internals; if Mastra re-reads the schema from a different source or freezes the instance, this silently regresses to the original failure — add a regression test that asserts tool.inputSchema is the Zod schema after init for the two whitelisted ids.
  • src/agent/mcp-client.ts:157 — override is keyed by firecrawl_firecrawl_scrape / firecrawl_firecrawl_search, but the actual tool name produced by getMCPTools depends on the server's reported tool names and the serverName_toolName join convention; if Firecrawl renames or the join differs, the override silently no-ops and calls fail again — log a warning when SCHEMA_OVERRIDES[name] exists but assignment is skipped, or assert the expected names at init.

Nits

  • mcp-servers.yaml:6url:/tools: are indented 7 spaces while the sibling brave block uses 8 for its children; align for consistency (valid YAML either way).

AvivK5498 and others added 2 commits June 23, 2026 00:14
…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>
@AvivK5498 AvivK5498 merged commit 433480c into main Jun 22, 2026
2 checks passed
@AvivK5498 AvivK5498 deleted the fix/mcp-draft-2020-12-schema branch June 22, 2026 21:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review-me Automated PR Review with Eve

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant