Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Tools and results

Register a typed tool so its published input schema and Rust handler argument remain paired by type.

extern crate component_shape_mcp;
fn main() -> Result<(), component_shape_mcp::McpToolError> {
#[derive(component_shape_mcp::McpToolInput)]
#[serde(rename_all = "camelCase")]
#[mcp(crate = component_shape_mcp)]
struct SearchArgs {
    #[serde(alias = "q")]
    query: String,
    page_size: Option<u32>,
}

let mut tools = component_shape_mcp::McpToolRegistry::new();

let tool = component_shape_mcp::tool_definition_for_input::<SearchArgs>(
    "search",
    Some("Search".to_owned()),
    None,
    None,
)?;

tools.add_typed_tool(tool, |args: SearchArgs| {
    component_shape_mcp::tool_structured_result(
        component_shape_mcp::serde_json::json!({ "query": args.query }),
    )
})?;

let server = component_shape_mcp::McpServer::from_tool_registry(
    "search-server",
    "1.0.0",
    tools,
);
Ok(())
}

This creates a server with one registered tool. It can now serve requests using the transport described in Servers and stdio.

Use the async registration methods when the handler returns a future. Use an untyped tool only when the integration must decode a dynamic argument set.

Execute Koruma domain rules

Derive koruma::Koruma alongside McpToolInput and register domain inputs through add_koruma_tool or add_koruma_tool_async. Koruma is the ecosystem’s canonical domain validator. The registry strictly decodes arguments, runs ValidateExt, then invokes the handler only on success. Async validation also precedes creating the handler’s future.

use koruma_collection::numeric::RangeValidation;

#[derive(component_shape_mcp::McpToolInput, koruma::Koruma)]
struct BatchArgs {
    #[koruma(RangeValidation::<_>.min(1).max(5))]
    count: u32,
}

fn main() -> Result<(), component_shape_mcp::McpToolError> {
let mut tools = component_shape_mcp::McpToolRegistry::new();
let tool = component_shape_mcp::tool_definition_for_input::<BatchArgs>(
    "batch", None, None, None,
)?;
tools.add_koruma_tool(tool, |args: BatchArgs| {
    component_shape_mcp::tool_structured_result(
        component_shape_mcp::serde_json::json!({ "count": args.count }),
    )
})?;
Ok(())
}

Add the koruma facade and koruma-collection for derives and built-in rules. component-shape-mcp uses the framework-neutral koruma-core runtime contracts. Server builders expose koruma_tool and koruma_tool_async. Applications retain rule selection, authorization, and handler policy.

Failures return Koruma’s structured form, field, and element issues through MCP, including source field names, labels, indices, and typed runtime parameters. McpValidationIssue::from(&issue) shares that conversion with domain adapters. Use koruma_validation_error(&error) to convert an error or validate_koruma after constructing an untyped input. Failed custom errors that enumerate no issues still return a form-level failure. Static schema rule descriptors and hints describe constraints to clients; domain validation executes the Koruma rules.

Add metadata

Store application-owned names, titles, descriptions, icons, and MCP annotation hints in McpToolMetadata. Use tool_definition_for_input_with_metadata when the metadata and typed input should be constructed together.

Registration validates names, required text, icons, schemas, duplicates, and incompatible annotation hints. Raw custom tool definitions registered through add_tool or add_tool_async receive the same checks.

Return structured results

Use tool_structured_result for a successful structured response. If the tool publishes an output schema, its successful structured_content must match that schema.

The registry compiles each output schema at registration and shares the validator across calls and registry clones. Direct calls, async calls, and MCP protocol calls all validate successful results. Invalid schemas fail definition construction or registration with InvalidSchema; missing or invalid structured content produces InvalidToolOutput. Handler error results bypass output validation. Error kinds and structured fields are stable; diagnostic text may change with the validator.

Output schemas use JSON Schema Draft 2020-12 when $schema is absent. Explicit Draft 4, 6, 7, 2019-09, and 2020-12 dialects are supported; unknown dialects are rejected. format remains annotation-only, including application formats such as language-tag. References must resolve within the supplied schema, including bundled $defs and identifiers. External retrieval is disabled for every URI scheme, including HTTP and local files, even if another dependency enables the validator’s retrieval features.

Return the exact advertised property and enum names. The input decoder’s aliases and x-mcp* metadata do not rename or normalize output. If a type serializes with different names from its deserialize-facing McpJsonSchema, supply an output schema that describes the serialized representation. Application data containing keys such as $ref or $schema remains data and is never retrieved as a schema.

Handler failures remain error results and may include a structured error object. McpToolError supplies stable error kinds and relevant fields so clients can branch on failures without parsing display text. Use validation_issues_error when one call must report multiple domain validation issues.