Changelog
Multicorn Shield Changelog
Everything that shipped in each release of the Shield SDK. New features, fixes, and security updates. All in one place.
Added
- Windsurf IDE as a supported platform in `npx multicorn-proxy init`. Generates a proxy config and prints an `~/.codeium/windsurf/mcp_config.json` snippet using the Windsurf `mcpServers` / `serverUrl` schema.
- Auto-detection of existing Windsurf proxy entries (shows "● detected locally" in the platform selection list).
Changed
- Next Steps block for Cursor and Windsurf rewritten as clear three-step numbered actions: download the IDE if needed, paste the config snippet, restart. Previous copy ("Config file: ...", "Restart Cursor to pick up MCP config changes") gave no guidance to first-time users.
Added
- New `--api-key <key>` CLI flag on `multicorn-proxy --wrap`. Lets users run the proxy without first creating a config file.
- New `MULTICORN_API_KEY` environment variable support. Resolves with priority `--api-key` flag > `MULTICORN_API_KEY` env var > `~/.multicorn/config.json`.
- New "Local MCP / Other" option in the `multicorn-proxy init` wizard. Skips the platform-specific setup steps and writes a minimal config suitable for wrapping any local MCP server with `--wrap`.
- SDK constructor now validates the API key format and rejects invalid keys (empty, wrong prefix, too short, or the literal placeholder `mcs_your_key_here`) with a clear error pointing at the settings page.
Changed
- `multicorn-proxy init` platform menu now labels detected platforms as "detected locally" instead of "connected", with a dimmed dot icon instead of a green checkmark. The previous label implied account-level connection state, but the underlying detection only checks for local config files.
- Error message when no API key is configured now mentions all three sources: the `--api-key` flag, the `MULTICORN_API_KEY` environment variable, and the `npx multicorn-proxy init` config file path.
- All references to the API keys settings page now use the fragment URL `https://app.multicorn.ai/settings#api-keys` instead of the previous `/settings/api-keys` path which did not exist.
Fixed
- `multicorn-proxy --wrap` now fails immediately at startup with a clear error if the configured API key is rejected by the Multicorn service. Previously the proxy logged "Agent resolved" and "Proxy ready" with empty agent state and only blocked tool calls at runtime, leaving users confused about why their setup was not working.
- `multicorn-proxy --wrap` now correctly accepts proxy flags (`--api-key`, `--base-url`, `--log-level`, `--dashboard-url`, `--agent-name`) when they appear between `--wrap` and the wrap command. Previously the parser bailed with "requires a command to run" because the early-exit guard rejected any flag-shaped token in that position before the stripping logic ran.
- `multicorn-proxy init` exit summary no longer renders a trailing dash for the "Local MCP / Other" option (which has no agent name). The summary line now reads `✓ Local MCP / Other` instead of `✓ Local MCP / Other -`.
- `multicorn-proxy init` no longer prints a misleading "Next steps" block referencing "Other MCP Agent" and `--agent-name` after the "Local MCP / Other" option. The "Try it" example printed inside the option 4 branch is sufficient guidance.
Added
- `readBaseUrlFromConfig()` helper for reading base URL from partial config files.
- `parseConfigFile()` shared helper eliminating duplicated file read/parse logic between `loadConfig` and `readBaseUrlFromConfig`.
- `isAllowedShieldApiBaseUrl()` exported validator for HTTPS/localhost scheme checks.
- `DEFAULT_SHIELD_API_BASE_URL` named constant replacing hardcoded fallback string.
- HTTPS scheme validation in `runInit()` init flow (previously only enforced in wrap flow).
Changed
- `runInit` parameter changed from `baseUrl = "https://api.multicorn.ai"` to `explicitBaseUrl?: string` to distinguish "no flag" from "explicitly passed default."
- Base URL resolution priority: explicit flag > full config > partial config > env var > default.
- HTTPS validation error messages no longer include the actual URL value.
- Wrap flow validates `--base-url` before loading config when the flag is present.
Fixed
- Proxy CLI `init` command now reads `baseUrl` from `~/.multicorn/config.json` on the new-key path, not just the reuse-key path. Previously required `--base-url` flag as a workaround.
- `--base-url` CLI flag correctly overrides config file value (previously indistinguishable from the default).
Fixed
- Updated README badges and npm package metadata to reflect current branding.
Added
- Multi-agent config support: `~/.multicorn/config.json` now stores an `agents` array with per-platform entries instead of a single `agentName`
- New CLI commands: `npx multicorn-proxy agents` (list configured agents) and `npx multicorn-proxy delete-agent <name>` (remove an agent)
- New exported helpers: `getAgentByPlatform()`, `getDefaultAgent()`, `collectAgentsFromConfig()`, `deleteAgentByName()`
- `AgentEntry` interface exported from the SDK
- Automatic migration: legacy single-agent configs are upgraded to the new format on first read and written back to disk
- Platform-based agent lookup in Claude Code hooks (`pre-tool-use.cjs`, `post-tool-use.cjs`), OpenClaw plugin, and Claude Desktop extension
- CLI agent name sanitisation: `delete-agent` strips non-printable characters before echoing to terminal
Changed
- `ProxyConfig` interface now includes optional `agents` (readonly `AgentEntry[]`) and `defaultAgent` fields
- `agentName` and `platform` fields on `ProxyConfig` are deprecated (kept for backward compatibility during migration)
- `runInit()` appends to the agents array instead of overwriting; detects duplicate platforms and prompts to replace
- Restored inline OpenClaw setup flow with version detection, auto-config of `~/.openclaw/openclaw.json`, and "Next steps" instructions (`openclaw gateway restart`, `openclaw tui`)
- Restored inline Claude Code setup instructions (marketplace add, plugin install, start claude, `/plugin` verification)
- "Next steps" summary restored at end of init wizard with per-platform instructions
- Help text clarified for non-technical users ("List configured agents and show which is the default", "Remove a saved agent")
- CJS hook duplication comment updated to explain why shared modules are not possible
Fixed
- Running `npx multicorn-proxy init` for a second platform no longer overwrites the first agent's config
- `delete-agent` clears `defaultAgent` when deleting the default agent instead of leaving a dangling reference
Security
- Agent names from CLI input are sanitised before echoing to stdout/stderr to prevent terminal escape sequence injection
Changed
- CLI rewrite: extracted platform selection, agent naming, and proxy config prompts into separate helper functions
- Reduced platform options from 4 (OpenClaw, Claude Code, Claude Desktop, Other MCP Agent) to 3 (OpenClaw, Claude Code, Cursor)
- Cursor connection detection via `~/.cursor/mcp.json`
- Claude Code connection detection via `~/.claude/plugins/cache/multicorn-shield`
- Cursor (selection 3) now prompts for target MCP server URL and creates a hosted proxy config via the Shield API
- Platform-specific MCP config snippets shown after proxy config creation
- "Connect another agent?" prompt changed from `(y/N)` default-no to `(Y/n)` default-yes
- Setup complete summary now shows agent names and proxy URLs alongside platform labels
Added
- Claude Desktop Extension (.mcpb) for one-click install. Packages Shield as a Desktop Extension that wraps existing MCP servers, enforces permissions via the Shield API, and logs all tool calls.
- `npx multicorn-shield restore` command to recover original MCP server config after disabling the extension.
- `multicorn-shield/proxy` subpath export with interceptor helpers, consent utilities, logger, scope validator, and tool mapper for hosted proxy consumers.
- HTTP client for hosted proxy URLs (`proxy-client`) supporting Streamable HTTP transport, session management, and JSON-RPC error handling.
- Optional extension setting `base_url` (env `MULTICORN_BASE_URL`) for enterprise or self-hosted Shield API endpoints. Defaults to `https://api.multicorn.ai` when empty.
Changed
- Desktop Extension routes tool calls to hosted proxy URLs over Streamable HTTP instead of spawning child MCP processes locally. Permission enforcement and audit logging now run server-side, avoiding sandbox limits in Claude Desktop.
- `runInit` base URL resolution checks config file and `MULTICORN_BASE_URL` env var before falling back to the default API endpoint.
- `platform` field threaded through proxy config and CLI init flow for connection method tracking in the dashboard.
Security
- Claude Code PreToolUse hook now fails closed when the Shield API is unreachable or returns an error. Previously, all error paths exited with code 0 (allow). Now, any error after config is successfully loaded exits with code 2 (block). This matches the fail-closed behaviour of the OpenClaw plugin and MCP proxy since v0.1.15.
Added
- Claude Code plugin: PreToolUse hook intercepts tool calls and checks permissions via Shield API before allowing execution
- Claude Code plugin: PostToolUse hook logs completed tool calls to Shield audit trail
- Claude Code plugin: consent screen opens in browser on first tool call for new agents, polls for approval
- Claude Code plugin: consent marker file prevents repeated browser opens after initial consent
- Claude Desktop: CLI wizard auto-writes `claude_desktop_config.json` with MCP proxy config (macOS, Linux, Windows paths)
- Claude Desktop: wizard prompts for MCP server command and merges config without clobbering existing entries
- MCP proxy: comprehensive tool name mapper with explicit mappings for filesystem, git, web, terminal, email, and calendar MCP servers
- CLI wizard: "connected" checkmark for Claude Code and Claude Desktop in platform selection menu
- CLI wizard: Step 3 added to Claude Code output ("Start Claude Code: claude")
- Agent name validation: must match /^[a-zA-Z0-9_-]+$/ before use in config files
- `shell` tool name mapping to terminal:execute in Claude Code hook (covers Claude Code's Shell tool variant)
Changed
- Claude Desktop wizard path now auto-writes config instead of showing manual JSON snippet (falls back to manual on invalid JSON or user skip)
- MCP proxy tool mapping replaced: `extractServiceFromToolName`/`extractActionFromToolName` underscore-split replaced with explicit `mapMcpToolToScope` lookup table
- `isClaudeDesktopConnected` uses proper args array inspection instead of substring match on serialized JSON
Fixed
- Claude Code plugin install: removed `skills` array from plugin.json that caused validation error on `claude plugin install`
- Claude Code consent flow: consent screen only opens once per agent (not per scope), subsequent permission requests block with approvals link
- Claude Code hook: localhost:8080 API base URL correctly maps to localhost:5173 dashboard URL for consent and approvals links
- MCP proxy: filesystem server tools (read_file, write_file, list_directory, etc.) now correctly map to filesystem:read/write instead of garbage service names
Added
- Claude Code marketplace manifest at `.claude-plugin/marketplace.json`
- Claude Code plugin structure at `plugins/multicorn-shield/` with plugin.json and shield-governance skill
- Repository field added to marketplace.json linking to GitHub source
Added
- `ShieldAuthError` class for clean 401/403 error propagation through `resolveAgentRecord`
- `buildInternalErrorResponse`, `buildServiceUnreachableResponse`, and `buildAuthErrorResponse` in interceptor module
- Early auth-invalid and offline-mode guards at the top of `handleToolCall` (before scope validation)
- `authInvalid` flag on `AgentRecord` for propagating auth failures from consent module to proxy
- `proxy.fail-closed.test.ts` covering service-down, timeout, 500, malformed JSON, 401, 403, and internal error scenarios
- `plugin.fail-closed.test.ts` covering exception handling, 5xx responses, and malformed response blocking
Changed
- All proxy and plugin failure modes now fail closed (block action when Shield cannot verify permissions)
- `handleHttpError` returns `shouldBlock: true` for 429 (rate limit) and 5xx (server error), matching the existing `checkActionPermission` behavior and fixing misleading comments
- Service-unreachable, auth-error, and internal-error responses use distinct JSON-RPC error codes: -32000 (permission denied), -32002 (internal error), -32003 (service unreachable), -32004 (auth error)
- Plugin output filename changed from `index.js` to `multicorn-shield.js` to fix OpenClaw plugin ID mismatch warning
Fixed
- Proxy `handleToolCall` no longer hangs or returns wrong error code when service is unreachable at startup
- `findAgentByName` wraps `response.json()` in try/catch so malformed responses flow through the offline path instead of throwing unhandled rejections
- Existing test assertions updated to match new error codes (-32003 for service unreachable, -32004 for auth errors)
Fixed
- Audit log payload column uses `text` instead of `jsonb` to preserve SHA-256 hash chain integrity (PostgreSQL `jsonb` normalizes key ordering and whitespace)
- `Instant.toString()` timestamp precision preserved using `DateTimeFormatter` with `SSSSSS` pattern in `AuditHasher.formatTimestamp()`
- All 40 integration tests passing after audit log migration (V030)
Fixed
- Consent screen now pre-selects the permission level the agent actually requested (e.g. terminal:execute pre-selects the Execute button)
- Scope param parsing supports both formats: service:permission (terminal:execute) and permission:service (execute:terminal)
- deriveDashboardUrl respects MULTICORN_BASE_URL env var for local development instead of always resolving to production
- Plugin re-checks permission after consent completes in the blocked path, so the user doesn't have to trigger a second tool call
Fixed
- Approval flow: plugin correctly handles consent-then-permission-check sequence
- Flaky tests stabilised across handler, plugin, proxy blocking, and edge-case suites
Fixed
- Plugin fail mode now defaults to closed (block on API error, never fail open)
- approval_id field name corrected from camelCase to snake_case to match backend API
- Plugin beforeToolCall wrapped in try/catch so errors block instead of crashing silently
- Config cascade documented: ~/.multicorn/config.json takes priority over openclaw.json plugin env
Fixed
- API key resolution from config.json when openclaw.json env block is not available
Fixed
- Plugin correctly maps destructive exec commands (rm, mv, sudo, chmod) to terminal:write instead of terminal:execute
- Approval descriptions now show human-readable summaries instead of raw shell commands
- Agent polling removed in favour of immediate block with dashboard redirect (OpenClaw hook timeout was shorter than human approval time)
Added
- README header SVG banner
Changed
- Consent flow updated for OpenClaw Plugin API (replaces deprecated gateway hook approach)
Fixed
- Handler and plugin consent test alignment with new Plugin API structure
Added
- Comprehensive plugin test suite for beforeToolCall and afterToolCall hooks
Fixed
- Plugin registration and lifecycle handling with OpenClaw Plugin API
Changed
- Package metadata updates for npm listing
Fixed
- Test stability improvements across the full suite
Changed
- MCP proxy improved for edge cases in tool call interception
Fixed
- Proxy test reliability
Added
- Shield API client (shield-client.ts) for permission checks and action logging from the plugin
- Consent flow module with browser-open and polling for user authorization
- OpenClaw Plugin API integration (beforeToolCall/afterToolCall hooks)
- Tool name mapper: OpenClaw tools (exec, read, write, browser, message) mapped to Shield service scopes
- Hook documentation (HOOK.md)
Fixed
- OpenClaw integration issues discovered during end-to-end testing
Changed
- Publish workflow switched to OIDC trusted publishing via GitHub Actions
Fixed
- Plugin loading path resolution for OpenClaw
Added
- Consent screen web component with Shadow DOM isolation, focus trapping, and keyboard navigation
- Scope system with hierarchical definitions, parsing, and validation
- Action logger for audit-trail recording of agent activity
- Spending controls with per-agent and per-scope limit checking
- MCP protocol adapter for Model Context Protocol integration
- TypeScript strict mode with full type safety across all modules
- ESM and CJS dual-format builds via tsup
- Full test suite with >85% coverage thresholds