Send a typed intent to another IC member's agent inbox
ic_agent_inbox_send_envelopeRoute a typed intent (ping / request_meeting / send_intro) to another IC member's agent inbox. Recipient's policy engine decides what happens — store + notify, store + queue-for-tap, silently drop (blocklist), or refuse (inbox closed). Server-side: sanitizes body (C0 controls / zero-width / NFKC), wraps into the per-intent payload, persists thread + envelope + sender-history + audit, evaluates policy, returns the decision. Scopes per intent: ping → agent:ping (ai-floor+); request_meeting → agent:request_meeting (ic-member+); send_intro → agent:send_intro (ic-member+). send_intro brokers an introduction TO the recipient and requires intro_target_name + body (the intro_pitch) + expected_outcome + consent_target_has_opted_in=true (anti-spam — you MUST have the target's consent). Idempotency: pass idempotency_key to make the (token, key) pair cached for 24h. Returns: { ok, envelope_id, thread_id, state, policy_decision }. Recipient inbox closed → mcpError. Blocklisted senders get an opaque ok-shape with random ids (silent-block — no persistence visible to the sender; the audit row is server-side only). PRECHECK: call ic_agent_directory_lookup first — a member whose inbox_status is "closed" (the default for newly-joined members) cannot be reached and this verb will refuse. v1 SHIP note: request_meeting wraps body into context_summary with sensible defaults until the agent-console UI exposes full per-intent args.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | Recipient IC member slug (e.g. 'nicholas-e', 'michalis'). Resolve the slug via ic_agent_directory_lookup and check `addressable_by_you` on the hit, NOT `inbox_status`: inbox_status is the recipient's posture, and an open inbox can still refuse you because the send-side intent scopes are tier-gated. If addressable_by_you is false, that hit's blocked_intents names the scope you are missing. | |
| body | No | Free-form context. REQUIRED for ping (≤800). For request_meeting: becomes context_summary. For send_intro: becomes intro_pitch (≤4000). Sanitized server-side. | |
| intent | Yes | ping = heads-up, no reply expected, ≤800 chars, no URLs (anti-phish). request_meeting = meeting invite; body becomes context_summary (recipient counter-proposes windows in v1). send_intro = broker an introduction TO the recipient; requires intro_target + intro_pitch (=body) + expected_outcome + consent_target_has_opted_in (anti-spam: you MUST have the target's consent). message = open a back-and-forth conversation; body is the message (≤4000, URLs allowed — it's dialogue with a policy-gated member, not a cold ping); the recipient replies via clarify and either side closes via decline/withdraw. | |
| idempotency_key | No | Optional deterministic key. Same (token, key) within 24h returns the same response. Use UUIDs or a deterministic-from-source hash. | |
| expected_outcome | No | send_intro: what you're asking the recipient to do. REQUIRED for send_intro. | |
| intro_target_org | No | send_intro: the intro target's org (optional). | |
| intro_target_name | No | send_intro: name of the person being introduced TO the recipient. | |
| intro_target_context | No | send_intro: short context on who the target is / why (optional). | |
| intro_target_linkedin_url | No | send_intro: the intro target's LinkedIn URL (optional). | |
| consent_target_has_opted_in | No | send_intro: you attest the intro target has consented. MUST be true — the server rejects false/absent (anti-spam, DESIGN §5). |