greentic-mcp 0.4.19

MCP ToolMap + WASIX/WASI executor bridge
Documentation
# Greentic MCP Tool Bridge

`greentic-mcp` provides the host-side tool registry and WASIX/WASI execution
bridge used by flows to invoke MCP tools compiled to WebAssembly. It loads a
declarative tool map, resolves tools by logical name, and executes them through
Wasmtime with per-tool timeouts, retry hints, and transient error handling.

## Component composer CLI

`greentic-mcp` ships a `greentic-mcp` CLI that composes a router component into
the bundled MCP adapter component. The result is the merged component that
flows reference.

```bash
greentic-mcp compose ./router.component.wasm -o ./merged.component.wasm
```

Notes:
- `wasm-tools` must be available in `PATH` (or set `GREENTIC_MCP_WASM_TOOLS`).
- The bundled adapter targets `wasix:mcp@25.06.18`.

The crate leans on the shared contracts published in
[`greentic-types`](https://docs.rs/greentic-types) and the WIT definitions plus
generated bindings in [`greentic-interfaces`](https://docs.rs/greentic-interfaces).
Tools are compiled for the WASI Preview2 target (`wasm32-wasip2`) and export a
canonical entrypoint that accepts and returns UTF-8 JSON payloads, so hosts no
longer have to marshal pointer/length pairs manually. When tools additionally
export the `greentic:component/component@1.0.0` world, the bridge calls
`describe-json` to fetch the node schema/defaults that live with the tool
component rather than mirroring them in this repository.

Runtime callbacks (HTTP + KV) are satisfied through the `runner-host-v1`
helpers shipped by `greentic-interfaces`, which keeps the host implementation
aligned with the latest Greentic runner contracts. Secrets must travel through
the `greentic:secrets/store@1.0.0` bytes API (no env/host-import fallback); the
legacy `secret_get` hook is removed and callers should provide a store binding
that enforces runtime TenantCtx scope.

## Tool map configuration

Tool metadata is loaded from JSON or YAML. Each entry records where the tool
artifact lives, the export to call, and optional execution hints.

```yaml
tools:
  - name: echo
    component: ./tools/echo.wasm
    entry: tool_invoke
    timeout_ms: 1000
    max_retries: 2
    retry_backoff_ms: 200
```

Use `greentic_mcp::load_tool_map` to parse the file and build a `ToolMap`.

```rust,no_run
use greentic_mcp::{invoke_with_map, load_tool_map, WasixExecutor};
use serde_json::json;
use std::path::Path;

# #[tokio::main]
# async fn main() -> Result<(), Box<dyn std::error::Error>> {
let map = load_tool_map(Path::new("toolmap.yaml"))?;
let executor = WasixExecutor::new()?;

let echoed = invoke_with_map(&map, &executor, "echo", json!({"hello": "world"}))
    .await?;

assert_eq!(echoed, json!({"hello": "world"}));
# Ok(())
# }
```

`WasixExecutor` ensures that traps bubble up as transient errors, applies
exponential backoff with jitter between retries, and converts wall-clock
timeouts into `McpError::Timeout`.

## ABI contracts

See [ABI.md](ABI.md) for the exact contract implemented by the integration
tests. When a tool exports the richer Greentic component API, use the bindings
from `greentic-interfaces` to avoid manual JSON marshalling and to work with
the `describe-v1`/`runner-host-v1` WIT worlds directly.

## Secret requirements

`describe_tool` now normalizes any secret descriptors in tool metadata to
`Vec<SecretRequirement>`:

- Prefer `secret_requirements` returned by `describe-json`.
- Fall back to legacy `list_secrets` payloads and emit a warning.
- Keys validated via `greentic-types`; unknown formats default to `text`.
- Default scope uses the runtime sentinel `{ env: "runtime", tenant: "runtime" }`
  so TenantCtx/session identity can override at execution time.