Addresses security concerns raised in PR review:
1. Dynamic headers now require explicit allowlist per server:
- New `dynamic_headers.allowed` config field lists permitted header names
- Without allowlist, no dynamic headers are forwarded (secure by default)
- Header names matched case-insensitively
2. Add limits to prevent abuse:
- `max_count`: max headers per request (default: 10)
- `max_value_len`: max value length (default: 4096)
3. Protect internal metadata in pico channel:
- Reserved keys (platform, session_id, conn_id, etc.) cannot be
overwritten by client-provided metadata
Example config:
```json
"dynamic_headers": {
"allowed": ["X-Grafana-Service-Account-Token"],
"max_count": 5,
"max_value_len": 2048
}
```
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Allows Pico clients to include a metadata object in message payloads.
String values are merged into the channel metadata, enabling clients
to pass headers (e.g., mcp:Authorization) that flow through to MCP
tool calls via the dynamic headers mechanism.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Clone header maps in WithMCPHeaders/MCPHeaders to prevent concurrent
mutation (maps are shared across goroutines via context).
- Trim whitespace from header names extracted from InboundContext.Raw
to prevent invalid HTTP header names.
- Add unit tests for headerTransport dynamic header injection:
dynamic-only, dynamic-overrides-static, and no-dynamic passthrough.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Channels can now pass HTTP headers to MCP servers on a per-request basis
by storing keys with a "mcp:" prefix in InboundContext.Raw. This enables
forwarding bearer tokens from channel authentication to MCP tool calls.
The context flows: Channel → InboundContext.Raw["mcp:Authorization"]
→ toolshared.MCPHeaders(ctx) → headerTransport.RoundTrip → HTTP header.
SSE/HTTP transports now always use headerTransport (previously only when
static headers were configured) so dynamic headers work out of the box.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add MCP section to config UI
* Handle MCP sse and URL-based server mapping
* Validate duplicate MCP server names before save
* Disable MCP discovery options based on mutual exclusivity in config section
Co-authored-by: Copilot <copilot@github.com>
* Clear stale MCP transport fields in patch payload
* Fix MCP config form state preservation and validation
* Avoid MCP form ID collisions for distinct server names
* Validate remote MCP URLs in config UI
* fix(config): correct MCP discovery merge patch behavior
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* fix(config): align MCP discovery semantics and MCP server editor behavior
* fix(config): validate MCP server fields only when active
---------
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Always route through classifySDKError to ensure resp.Body is
closed even when the API call succeeds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Store QuoteToken for image, video, and sticker messages (not just text)
- Add webhook.LocationMessageContent case to forward as [location] placeholder
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix bodyclose linter errors by ensuring resp.Body is closed
after all *WithHttpInfo SDK calls.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Address review feedback:
- Use *WithHttpInfo SDK variants to get HTTP response status codes
- Map status codes via ClassifySendError (429→ErrRateLimit, 5xx→ErrTemporary, 4xx→ErrSendFailed)
- Fall back to ClassifyNetError for network-level failures
- Configure SDK with 30s timeout HTTP client
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>