Summary
`crates/reach-cli/src/mcp.rs` defines a typed `ScrapeParams.extract: ExtractMode` enum with three variants:
```rust
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum ExtractMode {
#[default]
Text,
Html,
/// Extract a specific attribute value
#[serde(rename = "attr")]
Attribute { name: String },
}
```
But the corresponding JSON schema in `tool_definitions()` only declares two:
```rust
"extract": { "type": "string", "enum": ["text", "html"], "default": "text" },
```
So the Rust dispatch path will accept `{ "extract": { "name": "attr", "value": "href" } }` (or whatever the Attribute serialization shape is), but an MCP client introspecting the schema will never know that variant exists.
Fix
Update the schema entry to advertise the third variant. The schema for a tagged enum with a payload is a oneOf:
```json
"extract": {
"oneOf": [
{ "type": "string", "enum": ["text", "html"] },
{
"type": "object",
"required": ["attr"],
"properties": {
"attr": { "type": "object", "required": ["name"], "properties": { "name": { "type": "string" } } }
}
}
],
"default": "text"
}
```
(Actual shape depends on how serde renders the variant; verify with a unit test before shipping.)
While in there, add a unit test that round-trips a `ScrapeParams` with each variant through serde to lock the on-the-wire shape.
Discovered while
Reading the MCP module to audit the bindings during the todie/revenant CDP integration. Not blocking my work — I'm driving reach via the CLI not MCP — but worth filing because it's a silent capability gap for anyone using the MCP path.
Summary
`crates/reach-cli/src/mcp.rs` defines a typed `ScrapeParams.extract: ExtractMode` enum with three variants:
```rust
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum ExtractMode {
#[default]
Text,
Html,
/// Extract a specific attribute value
#[serde(rename = "attr")]
Attribute { name: String },
}
```
But the corresponding JSON schema in `tool_definitions()` only declares two:
```rust
"extract": { "type": "string", "enum": ["text", "html"], "default": "text" },
```
So the Rust dispatch path will accept `{ "extract": { "name": "attr", "value": "href" } }` (or whatever the Attribute serialization shape is), but an MCP client introspecting the schema will never know that variant exists.
Fix
Update the schema entry to advertise the third variant. The schema for a tagged enum with a payload is a oneOf:
```json
"extract": {
"oneOf": [
{ "type": "string", "enum": ["text", "html"] },
{
"type": "object",
"required": ["attr"],
"properties": {
"attr": { "type": "object", "required": ["name"], "properties": { "name": { "type": "string" } } }
}
}
],
"default": "text"
}
```
(Actual shape depends on how serde renders the variant; verify with a unit test before shipping.)
While in there, add a unit test that round-trips a `ScrapeParams` with each variant through serde to lock the on-the-wire shape.
Discovered while
Reading the MCP module to audit the bindings during the todie/revenant CDP integration. Not blocking my work — I'm driving reach via the CLI not MCP — but worth filing because it's a silent capability gap for anyone using the MCP path.