Skin

Kiwi MCP

built with rmcp SDK

Unified MCP server — the single entry point for AI agents. One connection gives access to every KiwiStack service: mail, calendar, contacts, tasks, docs, search, and more. Speaks Streamable HTTP (MCP over SSE).

License
Apache-2.0
Protocol
MCP/SSE
Port
8443
Language
Rust

MCP Tools

Meta-tools for discovery, plus the aggregated tool catalog from all registered services.

Meta
tools.list
List all available tools across all registered services. Returns name, description, and input schema for each.
service cursor
tools.describe
Get detailed information about a specific tool, including full JSON Schema for its parameters.
name
Aggregated Catalog (fan-out to services)
mail.*
Email operations: search, read, send, reply, archive. Proxied to Kiwi Mail.
5 tools
calendar.*
Calendar management: list events, create, find free slots, reschedule. Via Kiwi Mail.
4 tools
contacts.*
Contact operations: search, create, merge duplicates. Via Kiwi Mail.
3 tools
chat.*
Messaging: send messages, search history. Via Kiwi Chat (Phase 2).
Phase 2
tasks.* · projects.*
Project and task management. Via Kiwi Work (Phase 3).
Phase 3
docs.*
Knowledge base: create, read, update documents. Via Kiwi Docs (Phase 3).
Phase 3
search.*
Cross-service full-text search. Via Kiwi Search (Phase 2).
Phase 2
files.*
File storage operations. Via Kiwi Store (Phase 4).
Phase 4

Architecture

Single entry point for all AI agent interactions.

Kiwi MCP is the Skin layer — the outermost surface of the kiwi fruit. AI agents connect to a single MCP endpoint and get access to every tool from every service. No need to know which service handles what — Kiwi MCP routes tools/call requests to the right wrapper automatically.

Unlike other components, Kiwi MCP has no upstream binary. The rmcp SDK is a Rust library linked directly into the wrapper. This makes it a pure KiwiStack service — no two-process model, no upstream lifecycle management.

Flow: Agent → Kiwi Gate (TLS termination) → Kiwi MCP (JWT validation + tool routing) → fan-out to service wrappers (Kiwi Mail, Kiwi Chat, etc.) → aggregate responses → return to agent.

Request flow
AgentStreamable HTTP (MCP/SSE)
Kiwi Gate (10.10.20.1:443)
  ↓ TLS terminated, JWT forwarded
Kiwi MCP (10.10.20.19:8443)
  ↓ Route by tool namespace
Kiwi Mail (10.10.20.11:8443)  ← mail.*, calendar.*, contacts.*
Kiwi Chat (10.10.20.12:8443)  ← chat.*
Kiwi Work (10.10.20.14:8443)  ← tasks.*, projects.*

Config Reference

Wrapper configuration — lives at /etc/kiwi/config.toml.

config.toml
# kiwi-mcp configuration
listen_addr = "10.10.20.19:8443"
jwt_public_key = "/etc/kiwi/jwt-public.pem"
log_level = "info"

# Registered services (tool routing)
[[services]]
name = "kiwi-mail"
addr = "http://10.10.20.11:8443"
namespaces = ["mail", "calendar", "contacts"]

[[services]]
name = "kiwi-chat"
addr = "http://10.10.20.12:8443"
namespaces = ["chat"]

[[services]]
name = "kiwi-work"
addr = "http://10.10.20.14:8443"
namespaces = ["tasks", "projects"]
KeyTypeDescription
listen_addrstringBind address (private bridge)
jwt_public_keypathKiwi ID public key for JWT validation
services[].namestringService identifier for logging/metrics
services[].addrstringService wrapper HTTP address
services[].namespacesstring[]Tool namespaces routed to this service
log_levelstringTracing level: error, warn, info, debug, trace

Filesystem Layout

Simpler than other components — no upstream binary (rmcp is a library).

/
├── opt/
│   └── kiwi/                          # Kiwi MCP (Apache 2.0)
│       ├── bin/kiwi-mcp               # binary (rmcp SDK linked in)
│       └── version                    # "0.1.0"
├── etc/
│   └── kiwi/
│       ├── config.toml                # service config (see above)
│       └── jwt-public.pem             # Kiwi ID public key
├── var/
│   └── log/
│       └── kiwi/                      # JSON structured logs
└── run/

License

Fully Apache-2.0 — no copyleft concerns.

The rmcp SDK is licensed under Apache-2.0, the same license as KiwiStack itself. There are no copyleft obligations. Kiwi MCP is a pure Rust binary with no upstream process — the SDK is compiled directly into the binary.

This is the simplest licensing story in the KiwiStack catalog: everything is Apache-2.0, from the SDK to the wrapper to the configuration. No boundaries to manage, no file-level copyleft, no network isolation required.

Example Request

An MCP tools/call over Streamable HTTP.

Request
POST https://mcp.example.com/mcp
Content-Type: application/json
Authorization: Bearer <kiwi-id-jwt>

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "mail.search",
    "arguments": {
      "query": "quarterly report",
      "limit": 5
    }
  }
}
Kiwi MCP internally routes to Kiwi Mail, then returns
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [{
      "type": "text",
      "text": "Found 3 emails matching 'quarterly report'..."
    }],
    "isError": false
  }
}

Compatibility

Pinned versions — from compatibility.toml.

kiwi-mcp/compatibility.toml
# kiwi-mcp/compatibility.toml

[sdk]
name = "rmcp"
version = "0.1.5"

[wrapper]
version = "0.1.0"
rust_edition = "2024"
msrv = "1.85"

[tested]
date = "2026-02-28"
kiwi_id = "0.1.0"