Immersive Commons
Server Details
Members-run AI builder space on Floor 10, Frontier Tower SF. 138 tools: events, news, directory.
- Status
- Healthy
- Last Tested
- Transport
- Streamable HTTP
- URL
- Repository
- Immersive-commons/ic-skills
- GitHub Stars
- 0
Glama MCP Gateway
Connect through Glama MCP Gateway for full control over tool access and complete visibility into every call.
Full call logging
Every tool call is logged with complete inputs and outputs, so you can debug issues and audit what your agents are doing.
Tool access control
Enable or disable individual tools per connector, so you decide what your agents can and cannot do.
Managed credentials
Glama handles OAuth flows, token storage, and automatic rotation, so credentials never expire on your clients.
Usage analytics
See which tools your agents call, how often, and when, so you can understand usage patterns and catch anomalies.
Tool Definition Quality
Score is being calculated. Check back soon.
Available Tools
138 toolsfloor10_extract_event_metadataExtract event metadata from a URLRead-onlyInspect
Server-side WebFetch of an event page (Luma is the canonical case; LinkedIn / X / generic og:-bearing pages also work). Returns parsed { title, date, image, description, organization } so the agent doesn't have to scrape and parse OG / JSON-LD itself. Use the result to compose a HighlightStory. Args: { url }. Returns: a metadata map; empty fields where extraction missed.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes |
floor10_get_my_floor_memberGet my floor-member infoRead-onlyInspect
Confirms the calling agent token is valid and returns the floor-member it's scoped to. Use as a post-mint smoke check before submitting. Args: none. Returns: { member_id, member_name, token_prefix, scopes }.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
floor10_list_claimable_eventsList events I could write a highlight aboutRead-onlyInspect
Returns the list of events this floor member recently attended (or was invited to as a host) — the auto-discovery layer. Use this BEFORE asking the human 'what event did you go to?'; show them this list and let them pick. Source: graph.yaml attendance ingest, enriched with canonical URLs from data/events.yaml. Args: { status_filter? (e.g. ['checked_in','attended']), limit? (default 25, max 100) }. Returns: { count, total, generated_at, events: ClaimableEvent[] }. ClaimableEvent fields: event_api_id, title, date (YYYY-MM-DD), status (invited|approved|going|checked_in|attended), role, url, program, episode, registered_at, source.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Default 25; max 100. | |
| status_filter | No | Optional. Filter to one or more statuses. E.g. ["checked_in","attended"] for "really went". Default: all statuses (incl. "invited" so hosts see their own events). |
floor10_list_my_pendingPending highlights queue (count)Read-onlyInspect
Returns the count of pending highlight submissions across the full moderation queue. Useful as a 'is there a backlog?' probe before adding more. (Per-member filtering is not exposed for v1; the queue is small.) Args: none. Returns: { count }.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
floor10_submit_highlightSubmit a highlight to the moderation queueInspect
POST a HighlightStory for admin review. Same shape + same validation as the REST endpoint at /api/ingest/highlights/pending. Rate limit: 3 per token per UTC day. Re-submitting the same id refreshes the pending TTL (idempotent). Hard rules: no fabricated dates / quotes / member ids; news-wire third-person dek; candids first, posters last in images[]. See https://www.immersivecommons.com/docs/agent-submissions.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Slug pattern YYYY-MM-DD-<member-slug>-<event-slug>. Lowercase, alphanumeric + hyphens. | |
| dek | Yes | News-wire third-person, 1-2 sentences. No editorial verbs. No first person. No fabricated quotes. | |
| date | Yes | Display ("MAY 08") or ISO date. | |
| stats | No | Convention: RSVPS / ORGANIZATION / ROLE. | |
| action | Yes | Verb-clause completing "<member> <action> <event_title>". Lowercase. E.g. "spoke at", "hosted", "demoed at". | |
| images | Yes | Public URLs only (not base64). Candids first, posters / Luma covers last. Lead card cycles through these. | |
| event_url | No | ||
| member_id | No | Slug from data/members.yaml. The token attributes the submission server-side regardless. | |
| event_title | Yes | ||
| member_name | Yes | Display name as it should appear on the card. | |
| image_focals | No | Optional sparse map of subject focal points in [0, 1] coords (top-left origin). |
floor10_upload_imageUpload an image to the IC photo storeInspect
Re-hosts an image so its URL is suitable for the images array of a HighlightStory. Pass url (recommended; server fetches + stores) or data_url (small files only, RFC 2397 inline base64). Storage is content-addressed at floor10/highlights//. on Vercel Blob, public-readable, year-long cache. Idempotent: same bytes -> same URL. Rate limit: 30 uploads / token / UTC day (separate from the submission rate). Allowed types: image/jpeg|png|webp|gif|heic|heif|avif. Max 8 MB per upload. Returns: { url, bytes, content_type, sha256, deduped }.
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | Public URL of an image to fetch and re-host. Recommended path. http(s) only; localhost / cloud-metadata addresses are blocked. | |
| data_url | No | Inline data URL ("data:image/jpeg;base64,..."). Use for screenshots / small captures the agent generated locally. Capped at the same 8 MB ceiling; base64 has ~33% overhead so practical max is ~6 MB of source bytes. |
floorcast_effective_featuresWhich feature modules are LIVE on this floor (resolved)Read-onlyInspect
Resolve the effective feature-module set for the calling token's bound floor, LIVE from the tenant record: effective = (available ∩ enabled) \ force_disabled, plus the resolved tier and an 'N/total' breadcrumb (e.g. 'AI tier, 8/8 features live'). FAIL-CLOSED: on a both-down outage where the tenant record is unavailable, returns { ok:false, reason:'tenant-record-unavailable' } — NEVER a synthesized full set. Read-only; any valid token. Args: none. Returns: { ok, tenant, tier, available, enabled, force_disabled, effective, breadcrumb }.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
floorcast_my_rolesWhat can this token do on its floor (per-tenant roles)Read-onlyInspect
Introspect the calling token's per-(user, tenant) Floorcast roles on its bound floor. Returns the resolved ring + display label + the canActAs verdicts (member / floor-admin / super-admin). Resolves the SAME way the auth gate does (one shared resolver — no drift). On a token with no tied Clerk identity it returns the fail-open public shape. Read-only; no scope beyond a valid token. Args: none. Returns: { tenant, ring, role_label, can_act_as }.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
floorcast_preview_ai_curationPreview what the AI would surface on this floor (read-only)Read-onlyInspect
Read-only PREVIEW of the candidate content the floor's AI-curation policies WOULD surface, assembled from the floor's REUSED intel (commits / news / highlights). Writes NOTHING. Returns a per-policy { policy, candidate } list (candidate is null when the policy has no intel). Static-tier floors and floor10 (slug-fenced) return an empty list. Args: none.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
floorcast_pushPush a highlight to your floor (policy-routed)Inspect
Member push of a HighlightStory to your floor's MEMBERS WIRE, routed through the floor's content policy. Default policy 'moderation_queue' ⇒ the story lands PENDING for operator approval ({ ok:true, status:'pending', id }). A 'free_push_with_retract' floor (floor10 only this increment) ⇒ the story goes straight to ACTIVE ({ ok:true, status:'active', id }) — a deliberate policy bypass of the operator gate, retractable via floorcast_unpush. CONSEQUENTIAL. Typed refusals: { ok:false, reason } where reason is 'forbidden' (not a member on this floor), 'invalid' (story failed validation), 'approve-failed' (free_push: enqueued but the active-promotion failed; the pending record is left for operator visibility), or 'tenant-not-provisioned' (NON-floor10 push is currently DENIED — not 'lands in moderation_queue'; multi-tenant push ships in a follow-on). Same story shape + validation as floor10_submit_highlight. Args: the HighlightStory fields.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| dek | Yes | ||
| date | Yes | ||
| stats | No | ||
| action | Yes | ||
| images | Yes | ||
| event_url | No | ||
| member_id | No | ||
| event_title | Yes | ||
| member_name | Yes | ||
| image_focals | No |
floorcast_run_ai_curationRun AI curation now on this floor (Floor-Admin, consequential)Inspect
Manual fire of the floor's AI-curation runner: assembles a candidate per enabled policy from REUSED intel and pushes it through the inc-6 moderation primitives as 'system:ai_curation'. Non-floor10 AI floors land the candidate PENDING (operator-gated). Floor-Admin gated. Static floors return { ok:false, reason:'feature-not-available' }; floor10 is slug-fenced and ALSO denied (absolute in inc-7). De-dups against the active + pending lists so a re-run does not poison the pending queue. Args: none. Returns: a per-policy result list.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
floorcast_set_ai_policySet the AI-curation policy list on this floor (Floor-Admin)IdempotentInspect
Floor-Admin (operator-on-this-floor) sets the declarative AI-curation policy list (ai_policies) that drives the floor's AI self-updating wall. PERSISTS the tenant record via the inc-6 writer. Runs the FULL authz gate first: a non-Floor-Admin gets { ok:false, reason:'forbidden' } (no write). A live KV write failure surfaces { ok:false, reason:'write-failed', error }. Each policy is { type: 'top_commit'|'latest_news'|'rotate_highlights', enabled?, max_items? }. On success returns { ok:true, record }. Scope: a valid floor-bound token. Args: { policies }.
| Name | Required | Description | Default |
|---|---|---|---|
| policies | Yes | The AI-curation policy list to persist on this floor. |
floorcast_set_feature_availabilitySet a feature module AVAILABLE on this floor (Super-Admin)IdempotentInspect
Super-Admin (apex flag AND operator-on-THIS-floor) sets which modules a floor is ALLOWED to enable. PERSISTS the tenant record (inc-6). Runs the FULL per-tenant super-admin gate first: a floor-admin WITHOUT the apex flag, or a super-admin on a DIFFERENT floor, gets { ok:false, reason:'forbidden' } (no write). A live KV write failure surfaces { ok:false, reason:'write-failed', error } (no 500). On success returns { ok:true, record }. NOTE: the force-disable kill-switch (setForceDisabled) is intentionally NOT exposed as an MCP verb this increment — it stays human/lib-only as a deliberate safety posture (re-evaluated when the inc-7 human override console lands). Args: { module, available }.
| Name | Required | Description | Default |
|---|---|---|---|
| module | Yes | Module id (one of the 8 enum modules). | |
| available | Yes | true to make available, false to remove. |
floorcast_set_feature_enabledToggle a feature module ENABLED on this floor (Floor-Admin)IdempotentInspect
Floor-Admin (operator-on-this-floor) toggles a module in the floor's ENABLED set; a module must be AVAILABLE on the floor to enable. PERSISTS the tenant record (inc-6). Runs the FULL authz + availability gate first: a non-Floor-Admin, or enabling a module not available on the floor, gets { ok:false, reason:'forbidden' } (no write). A live KV write failure surfaces { ok:false, reason:'write-failed', error } (no 500). On success returns { ok:true, record } (the persisted next-record). Scope: a valid floor-bound token. Args: { module, enabled }. floorcast_effective_features reflects the toggle on the next read.
| Name | Required | Description | Default |
|---|---|---|---|
| module | Yes | Module id (one of the 8 enum modules). | |
| enabled | Yes | true to enable, false to disable. |
floorcast_unpushRetract your OWN pending highlightInspect
Member retract of your OWN still-pending highlight from your floor's queue (you cannot retract an already-approved/active item via this verb — that needs an operator). Routed through the floor content policy; the gate is server-side (ownership-checked). CONSEQUENTIAL. Returns { ok:true, id } on success; typed refusals { ok:false, reason } where reason is 'forbidden' (not your submission), 'not-found' (no such pending item), or 'tenant-not-provisioned' (NON-floor10 is currently DENIED). Args: { id }.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The pending highlight id to retract. |
ic_activity_get_recentRead the calling user's agent-activity logRead-onlyInspect
Returns the most recent activity events recorded for the calling user — every consequential tool call (highlights submit, RSVP, booking, GitHub link, opt-in toggle, tier request, directory search) ends up here with attribution to the token that made it. Each event has { ts, tool, scope, token_prefix?, token_label?, via, success, error?, meta? }. Useful for the human to audit 'which of my agents has been doing what.' Args: { limit?: number (max 100, default 25) }. Required scope: membership:read.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | How many recent events to return. Default 25, capped at 100. |
ic_admin_agent_audit_searchSearch class-B integration activity across members (operator)Read-onlyInspect
Cross-member audit search over class-B integration activity (DESIGN §11). Walks the matching clients → their bearer tokens → those tokens' outbox threads → each thread's actions, newest-first. Surfaces actions reachable from a client's OWN outbox (the integration's blast radius); counterparty-side actions are out of v1 scope (no reverse index yet). Operator-only (admin:agent_clients + live operator re-check). Args: { client_id?: string, operator_human?: string, member_id?: string, kind?: 'policy_eval'|'member_tap'|'system'|'counterparty', since?: ISO datetime, limit?: number (default 200), offset?: number (default 0) }. Returns: { ok, hits, total, has_more } — total counts every filtered hit; page past the cap with offset. Required scope: admin:agent_clients.
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | Restrict to one action kind. | |
| limit | No | Cap on returned actions, newest-first (default 200). | |
| since | No | ISO datetime lower bound — only actions at/after this. | |
| offset | No | Pagination offset into the filtered newest-first list (default 0). | |
| client_id | No | Restrict to one client's actions. | |
| member_id | No | Restrict to actions whose thread is addressed TO this recipient. | |
| operator_human | No | Restrict to one operator-of-record's clients. |
ic_admin_agent_client_listList class-B agent-client integrations (operator)Read-onlyInspect
List provisioned class-B integrations newest-first with usage stats (tokens issued, threads started, last seen). Operator-only (admin:agent_clients + live operator re-check). Secret hashes are never returned. calls_per_day / rejection_rate render absent until a per-call counter lands (v1 has none). Args: { include_revoked?: boolean (default true), limit?: number, offset?: number }. Returns: { ok, clients, has_more } — page past the cap with offset. Required scope: admin:agent_clients.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max clients (default 200). | |
| offset | No | Pagination offset (default 0). | |
| include_revoked | No | Include revoked clients (default true). |
ic_admin_agent_client_registerRegister a class-B agent-client integration (operator)Inspect
Provision an external integration (another company's CRM bot, a research-collab tool) with a client_id + one-time client_secret it later exchanges for a scoped bearer token (DESIGN §2 Class B). Operator-only: gates on admin:agent_clients AND a live operator-tier re-check. The plaintext secret is returned EXACTLY ONCE (only its hash is stored) — a lost secret means re-register. Grantable scopes are limited to the agent:* family (directory:read / request_meeting / send_intro / ping / thread:write / inbox:read / policy:read); any other requested scope (esp. admin:*) is REFUSED and listed in denied_scopes. Args: { name, operator_human, scopes: string[], contact, autonomy?, requires_signature?, budget_overrides? }. Returns: { ok, client_id, client_secret_once, client }. Required scope: admin:agent_clients.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Display name of the integration (e.g. 'Skew meeting bot'). | |
| scopes | Yes | Explicitly-enumerated scopes — must be a non-empty subset of the grantable agent:* family. Non-grantable scopes are refused (denied_scopes). | |
| contact | Yes | Contact for the operator-of-record (email / handle / URL) so a revoke decision has a human to reach. | |
| operator_human | Yes | The human operator-of-record who vouches for this integration. | |
| requires_signature | No | When true, the eventual bearer must ALSO carry a valid Ed25519 signature (the pubkey is bound at grant time). |
ic_admin_agent_client_revokeRevoke a class-B agent-client integration (operator)DestructiveInspect
Revoke an integration and flag its AUTONOMOUS actions for recipient re-confirmation (DESIGN §9 — interactive actions are NOT flagged, each had per-call approval). Revokes every linked bearer token so the integration is dead immediately, snapshots prior state for one-step revert (DESIGN §18), and returns how many autonomous actions were flagged + tokens revoked. Operator-only (admin:agent_clients + live operator re-check). Idempotent. Args: { client_id: string (cli_), reason: string }. Returns: { ok, actions_flagged, tokens_revoked }. Required scope: admin:agent_clients.
| Name | Required | Description | Default |
|---|---|---|---|
| reason | Yes | Why the integration is being revoked — recorded on the client record + rollback snapshot. | |
| client_id | Yes | The cli_<base32> id from ic_admin_agent_client_list. |
ic_admin_approve_eventApprove a pending member-event-request draft (operator)IdempotentInspect
Approve a pending 'save the date' event draft: flows the wrapped KioskEvent into floor10:events:approved (dedupe-prepend, keep newest 50), drops it from the pending queue, and writes an audit entry. The kiosk events page merges approved drafts with the live Luma list (live wins on the shared slug); once the real Luma event goes live, ic.kv_push.push_events prunes the draft automatically. This NEVER creates a public Luma event — it posts a no-RSVP save-the-date card; IC staff create the live Luma event from the request detail afterward. Two-step: omit confirm (or pass false) for a dry-run preview that returns what the call would do without mutating; pass confirm: true to actually apply. Idempotent: a missing / already-handled / TTL-expired id returns ok:false (and cleans the stale list pointer). Rate-limited to 20 approve+reject mutations per token per UTC day; dry-run calls do NOT count. Args: { id, confirm? }. Returns: dry-run shape on confirm=false; { ok, id } on confirm=true. Required scope: admin:events_review.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The pending event id to approve — the draft slug (e.g. 'demo-night-a1b2c3'), as returned by ic_admin_list_pending_events / ic_events_request. | |
| confirm | No | Set to true to actually mutate. When false / omitted, returns a dry-run preview that does NOT change state and does NOT count against the daily rate limit. |
ic_admin_approve_highlightApprove a pending highlight, publish to the wire (operator)IdempotentInspect
Promote a pending highlight into the live /floor10/highlights MEMBERS WIRE (dedupe-prepend, keep 4 active, spill older to archive), drop it from the queue, and write an audit entry. Idempotent: a missing or expired id returns ok:false. Scope: admin:highlights_review.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The pending highlight id to approve (the submission slug). |
ic_admin_approve_key_requestApprove a Z.ai key request → mint the key (operator)IdempotentInspect
Approve a pending Z.ai key request and MINT the proxy key. Two-step: omit confirm (or pass false) for a dry-run preview of the exact proxy block that would be minted; pass confirm: true to mint. IDEMPOTENT on request_id — a second confirmed approve returns the SAME key (it does NOT mint a second key); the plaintext key is surfaced ONLY on the first mint. For member keys, multiplier overrides the requested multiplier. The minted key works ONLY against the IC→Z.ai gateway (it carries zero IC tool scopes). Rate-limited to 20 approve+deny mutations per token per UTC day; dry-run + idempotent re-approve do NOT count. Args: { request_id, multiplier?: 1|2|5|10|20, confirm? }. Returns dry-run shape on confirm=false; on the first confirm:true mint, { ok, minted:true, agent_token, token_prefix, proxy }. Required scope: admin:llm_keys.
| Name | Required | Description | Default |
|---|---|---|---|
| confirm | No | Set to true to actually mint. When false / omitted, returns a dry-run preview that does NOT mint and does NOT count against the daily rate limit. | |
| multiplier | No | Member keys only: override the requested weekly-token multiplier. Ignored for workshop keys. | |
| request_id | Yes | The id of the pending request (from ic_admin_list_pending_key_requests). |
ic_admin_approve_ownershipApprove a founder-binding claim (operator)IdempotentInspect
Bind the requesting founder onto the StartupProfile, drop the request from the queue, write the active-ownership index + an audit entry. Once bound, that founder's agent/session may edit the page + post news. MULTI-OWNER + ADDITIVE: a startup may have many co-founders; approving ADDS the requester to the owner set (the first owner becomes the primary founder_clerk_user_id, each subsequent one is appended) — NO existing owner is ever displaced, so there is no rebind/confirm step. Idempotent: re-approving an existing owner, or a missing/expired id, is a clean no-op (ok:false only on missing/expired). Args: { id }. (confirm/force are accepted for back-compat but ignored.) Returns { ok, id, slug, founder_clerk_user_id, current_owners }. Required scope: admin:ownership_review.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The pending ownership request id to approve. | |
| force | No | Deprecated/no-op alias for confirm — additive approve never needs it. | |
| confirm | No | Deprecated/no-op. Multi-owner approval is additive (no owner is displaced), so no confirmation is needed. Accepted for back-compat. |
ic_admin_approve_tier_requestApprove a pending membership-tier request (operator)IdempotentInspect
Approve a pending tier request and set the user's tier. Two-step: omit confirm (or pass false) for a dry-run preview that returns what the call would do without mutating state. Pass confirm: true to actually apply. If tier is omitted, the user is approved to the tier they requested; pass tier to override (e.g. they asked for ic-member but you approve ai-floor). Rate-limited to 20 approve+deny mutations per token per UTC day; dry-run calls do NOT count. Args: { user_id, tier?: 'ft-member'|'ai-floor'|'ic-member'|'operator', reason?, confirm? }. Returns: dry-run shape on confirm=false; { ok, user_id, from, to, action: 'approve' } on confirm=true. Required scope: admin:tier_review.
| Name | Required | Description | Default |
|---|---|---|---|
| tier | No | Optional override. If omitted, approves the user to the tier they requested. 'operator' is approvable here even though it isn't self-requestable. | |
| reason | No | Optional note recorded in the audit trail. | |
| confirm | No | Set to true to actually mutate. When false / omitted, returns a dry-run preview that does NOT change state and does NOT count against the daily rate limit. | |
| user_id | Yes | Clerk user_id of the pending requester. |
ic_admin_deny_key_requestDeny a pending Z.ai key request (operator)DestructiveIdempotentInspect
Deny a pending Z.ai key request. Marks it denied + removes it from the queue; no key is minted. Two-step: omit confirm (or pass false) for a dry-run preview, confirm: true to apply. Refuses to deny an already-approved request (revoke the minted key at /floor10/agent-console instead). Rate-limited to 20 approve+deny mutations per token per UTC day; dry-run does NOT count. Args: { request_id, reason?, confirm? }. Returns dry-run shape on confirm=false; { ok, request_id, was_pending } on confirm=true. Required scope: admin:llm_keys.
| Name | Required | Description | Default |
|---|---|---|---|
| reason | No | Optional note recorded in the audit trail. | |
| confirm | No | Set to true to actually deny. When false / omitted, returns a dry-run preview that does NOT mutate and does NOT count against the daily rate limit. | |
| request_id | Yes | The id of the pending request to deny. |
ic_admin_deny_tier_requestDeny a pending membership-tier request (operator)DestructiveIdempotentInspect
Deny a pending tier request. Clears the pending fields + KV snapshot; the user's tier is unchanged. Two-step: omit confirm (or pass false) for a dry-run preview. Pass confirm: true to actually apply. The optional reason is recorded in the audit log and is surfaced to the requester on their /membership page so they understand why. Rate-limited to 20 approve+deny mutations per token per UTC day; dry-run calls do NOT count. Args: { user_id, reason?, confirm? }. Returns: dry-run shape on confirm=false; { ok, user_id, tier, was_pending } on confirm=true. Required scope: admin:tier_review.
| Name | Required | Description | Default |
|---|---|---|---|
| reason | No | Optional note. Recorded in the audit trail and shown to the requester on their /membership page. | |
| confirm | No | Set to true to actually mutate. When false / omitted, returns a dry-run preview that does NOT change state and does NOT count against the daily rate limit. | |
| user_id | Yes | Clerk user_id of the pending requester. |
ic_admin_leaderboard_inspectInspect the commits leaderboard + aggregation diagnostics (operator)Read-onlyInspect
Operator-only deep read of the commits leaderboard snapshot: the full ranked board PLUS the persisted aggregation errors[] (broken OAuth/PAT tokens, GraphQL failures captured during the weekly cron — the ops visibility operators need to spot N broken tokens before they wreck the next refresh) and the snapshot freshness (generated_at, stale, age_min). Each member carries { rank, handle, name, commits, private? } (private = folded-in private-contribution COUNT, never repo content). Returns: { ok, generated_at, stale, age_min, member_count, members: [...], errors: [{ userId, reason }] }. Required scope: admin:leaderboard_review.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | How many ranked members to return. Default 500, capped at 500. |
ic_admin_list_feedbackList agent feedback queue (operator)Read-onlyInspect
Read the agent-voice queue. Default returns the newest 25 summaries (preview = first 200 chars of message + attribution + priority + kind + resolved flag). Pass full=true to get full records (for export / triage). Filters AND together: kind, priority, resolved (true = closed only, false = open only, omit = both). Returns: { ok, count, total, scanned, filter, records }. Newest first. Required scope: admin:feedback_review.
| Name | Required | Description | Default |
|---|---|---|---|
| full | No | If true, return full FeedbackRecord (incl. ip_hash, contact). Default false = summaries. | |
| kind | No | Filter to one kind. | |
| limit | No | Default 25; max 200. | |
| offset | No | Paging cursor. Default 0. | |
| priority | No | Filter to one priority. | |
| resolved | No | Tri-state. true = resolved only, false = open only, omit = both. |
ic_admin_list_membersList IC members / accounts (operator)Read-onlyInspect
The ACTUAL account roster — every Clerk-backed IC account with its live ring/tier, resolved from Clerk (not the carded ic_directory_search, which only shows members who've set a profile card, and not the curated kiosk list). This is what you want to answer 'who are the members' or find a specific account (e.g. one that hasn't set a card yet). Each member: { user_id, name, email, tier ('public'|'ft-member'|'ai-floor'|'ic-member'|'operator'), pending_request (the tier they've requested but not yet been granted, or null), created_at }. Args: { tier?: filter to one ring; q?: case-insensitive name/email/user_id substring filter; limit?: number (default 200, max 500); offset?: number (default 0) }. Filters apply to the fetched page; total is the full Clerk account count and has_more tells you to page with offset (default limit covers all IC accounts in one page today). Required scope: admin:tier_review.
| Name | Required | Description | Default |
|---|---|---|---|
| q | No | Case-insensitive substring match on name / email / user_id. | |
| tier | No | Filter the page to accounts currently at this ring. | |
| limit | No | Page size (default 200). | |
| offset | No | Page offset (default 0). |
ic_admin_list_pending_eventsList pending member-event-request drafts (operator)Read-onlyInspect
Operator review queue: every pending 'save the date' event draft awaiting approval at /floor10/admin/events, plus a recent decisions/audit tail. Two sources feed the queue (the source field disambiguates): 'member_request' (a member's agent via ic_events_request) and 'kiosk_submit' (Ray's events kiosk-submit CLI). Each pending record: { id, title, when, venue?, host?, description?, source, requested_by?, submitted_at, submitted_by, request? } — request carries the extra Luma-shaped fields the kiosk card doesn't render (end / capacity / visibility / contact). Each audit entry: { id, action ('approve'|'reject'), by_clerk_user_id, at, reason?, title?, when? }. Use BEFORE ic_admin_approve_event / ic_admin_reject_event to see what's waiting and why. Args: { audit_tail?: number (default 12, max 500), detail?: 'summary'|'full' (default 'full'; 'summary' trims each pending row to id/title/when/source/submitted_at) }. Returns: { ok, count, pending, audit }. Required scope: admin:events_review.
| Name | Required | Description | Default |
|---|---|---|---|
| detail | No | Response weight. 'full' (default) returns every pending field per row incl. description + the nested Luma-shaped request; 'summary' trims each pending row to { id, title, when, source, submitted_at } for cheap queue triage. | |
| audit_tail | No | How many recent decisions to include. Default 12; max 500. |
ic_admin_list_pending_highlightsList pending MEMBERS WIRE highlights (operator)Read-onlyInspect
Operator review queue: every pending highlight submission with its id, member, action, event title, date, dek, and image count, so you can decide approve/reject. Excludes test fixtures + stale pointers. Pair with ic_admin_approve_highlight / ic_admin_reject_highlight. Args: { detail?: 'summary'|'full' (default 'full'; 'summary' trims each row to id/member_name/action/event_title/date) }. Scope: admin:highlights_review.
| Name | Required | Description | Default |
|---|---|---|---|
| detail | No | Response weight. 'full' (default) returns every review field per row; 'summary' trims each row to { id, member_name, action, event_title, date } for cheap queue triage. |
ic_admin_list_pending_key_requestsList pending Z.ai key requests (operator)Read-onlyInspect
Returns the operator's pending Z.ai-key-request queue plus a recent audit tail. Each pending record: { id, kind ('workshop'|'member'), requester_clerk_user_id, requester_name?, event_id?, event_title?, multiplier?, note?, created_at }. Use BEFORE ic_admin_approve_key_request / ic_admin_deny_key_request. Args: none. Required scope: admin:llm_keys.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_admin_list_pending_ownershipList pending startup-ownership claims (operator)Read-onlyInspect
Operator review queue: every pending founder-binding request — { id, member_id, member_name, startup_slug, startup_name, submitted_at, submitted_by_clerk_user_id, expires_at?, already_owned, current_owner?, current_owners? }. Multi-owner: already_owned now just flags that the slug already has >=1 owner — it is INFO, not a conflict (approving ADDS the requester as a co-founder; current_owners lists the existing set). Pair with ic_admin_approve_ownership / ic_admin_reject_ownership. Args: none. Returns { ok, count, pending }. Required scope: admin:ownership_review.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_admin_list_pending_tier_requestsList pending membership-tier requests (operator)Read-onlyInspect
Returns the operator's pending-membership queue plus the most recent audit tail. Each pending record: { user_id, email, display_name, current_tier, requested_tier, note, submitted_at }. Each audit entry: { user_id, email, action ('approve'|'deny'|'auto-promote'|'request'|'demote'), from, to?, requested?, reason?, by_clerk_user_id?, at }. Use BEFORE ic_admin_approve_tier_request / ic_admin_deny_tier_request to see who's waiting and why. Args: none. Required scope: admin:tier_review.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_admin_list_recent_startup_contentList recently-posted startup content for review (operator)Read-onlyInspect
Flat, newest-first list of recent startup news items (one row per item) for the auto-publish safety net. 'Recent' = posted within days (default 7) OR the parent profile was edited in that window. Each row: { slug, startup_name, public_visible, item_id, title, url?, posted_at, source?, profile_updated_at }. A hidden profile still surfaces its rows so you can see + restore what you took down. Pair with ic_admin_takedown_startup_content. Args: { days?: number (default 7) }. Returns { ok, count, rows }. Required scope: admin:content_review.
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | Lookback window in days (default 7). |
ic_admin_reject_eventReject a pending member-event-request draft (operator)DestructiveIdempotentInspect
Reject a pending 'save the date' event draft: drops it from the pending queue with an optional reason and writes an audit entry. Does NOT publish anything. Two-step: omit confirm (or pass false) for a dry-run preview; pass confirm: true to actually apply. The optional reason is recorded in the audit log (operator-facing; member requests do not surface it back to the requester today). Idempotent — rejecting an already-gone id still records the decision and returns ok. Rate-limited to 20 approve+reject mutations per token per UTC day; dry-run calls do NOT count. Args: { id, reason?, confirm? }. Returns: dry-run shape on confirm=false; { ok, id } on confirm=true. Required scope: admin:events_review.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The pending event id to reject — the draft slug. | |
| reason | No | Optional moderator note, recorded in the audit log. | |
| confirm | No | Set to true to actually mutate. When false / omitted, returns a dry-run preview that does NOT change state and does NOT count against the daily rate limit. |
ic_admin_reject_highlightReject a pending highlight (operator)DestructiveIdempotentInspect
Drop a pending highlight from the moderation queue with an optional reason and write an audit entry. Does not publish. Scope: admin:highlights_review.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The pending highlight id to reject (the submission slug). | |
| reason | No | Optional moderator note, recorded in the audit log. |
ic_admin_reject_ownershipReject a founder-binding claim (operator)DestructiveIdempotentInspect
Drop a pending founder-binding request from the queue (no bind) with an optional reason, and write an audit entry. Args: { id, reason? }. Returns { ok, id, slug? }. Required scope: admin:ownership_review.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The pending ownership request id to reject. | |
| reason | No | Optional moderator note, recorded in the audit log. |
ic_admin_resolve_feedbackResolve a feedback ticket (operator)IdempotentInspect
Mark one ticket resolved with an optional note. Two-step: omit confirm (or pass false) for a dry-run preview that returns the would-be-updated record without mutating. Pass confirm: true to actually apply. Already-resolved tickets return error_kind 'already_resolved' (idempotent at the channel level — no double-write of resolved_at). Args: { ticket_id, note?, confirm? }. Returns: dry-run shape on confirm=false; { ok, record } on confirm=true. Required scope: admin:feedback_review.
| Name | Required | Description | Default |
|---|---|---|---|
| note | No | Optional resolution note. Recorded on the record. Useful for 'shipping in v1.18' or 'wontfix — out of scope'. | |
| confirm | No | Set true to actually mutate. When false / omitted, returns a dry-run preview that does NOT change state. | |
| ticket_id | Yes | ticket_id from a prior submit (format fb_*). |
ic_admin_takedown_startup_contentTake down a startup news item or hide a whole profile (operator)DestructiveInspect
Pull auto-published founder content. With item_id: remove that single news item from the profile's news[]. Without item_id: hide the WHOLE startup (public_visible=false). Both rebuild the public cards, mirror to blob, revalidate the public pages, and write an audit entry. Idempotent (removing an already-gone item / hiding an already-hidden profile returns ok:true). NB: a removed news item cannot be restored — the founder must re-post it. Args: { slug, item_id?, reason? }. Returns { ok, slug, item_id?, scope }. Required scope: admin:content_review.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | Yes | The startup slug to act on. | |
| reason | No | Optional moderator note, recorded in the audit log. | |
| item_id | No | News item id to remove. Omit to hide the whole profile. |
ic_agent_directory_lookupFind addressable IC members + their inbox postureRead-onlyInspect
Search the member directory (floor roster + canonical members) for members you could address, annotated with each member's inbox_status (open/closed) and accepted_intents (best-effort — which intent types their policy will entertain; empty when closed). This is a routing HINT ('don't bother sending a meeting_request to a closed inbox'), not the authoritative decision — the policy engine still evaluates the real envelope. Closed-inbox members are still returned so you see they exist. Args: { query: string (2-80 chars), limit?: number (default 20, max 50) }. Returns: { ok, query, count, results: [{ member_id, member_name, inbox_status, accepted_intents }] }. Required scope: agent:directory:read.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Default 20, max 50. | |
| query | Yes | Name / display-name / member-id fragment, 2-80 chars. |
ic_agent_inbox_blockBlock a sender from my agent inboxInspect
Add an entry to YOUR inbox blocklist (the policy.blocklist your policy engine consults before any rule). Future envelopes from a blocked sender are silently dropped — they get an opaque ok-shape and never learn they're blocked. Specify EXACTLY ONE of operator / member / client. Idempotent (re-blocking an existing entry is a no-op success). Optional reason is recorded on a server-side audit row only (the blocklist itself stores no reason). The owner is always you (the token's member_id) — you can only manage your own blocklist. Args: { operator?: string, member?: string, client?: string, reason?: string }. Returns: { ok, blocklist, changed }. Required scope: agent:inbox:write. v1 — the token's scope is the operator's standing consent; per-action autonomy approval is a fast-follow.
| Name | Required | Description | Default |
|---|---|---|---|
| client | No | Block by agent_client client_id (class-B). | |
| member | No | Block by member_id. | |
| reason | No | Optional note — recorded on a server-side audit row, NOT on the blocklist entry. | |
| operator | No | Block by operator_human (the human behind the sending token). |
ic_agent_inbox_get_threadFetch one agent-inbox thread + envelopes + auditRead-onlyInspect
Returns the full thread record, every envelope in the conversation, and the audit-action log. Caller must be either the recipient (thread.parties.to.member_id matches token's member_id) OR the original sender (thread.parties.from.token_sha256 matches token's sha256). Otherwise returns 'thread_not_found' (404-shape — does not leak that a thread exists for someone else). Args: { thread_id: string (thr_) }. Returns: { ok, thread, envelopes, actions }. Required scope: agent:inbox:read.
| Name | Required | Description | Default |
|---|---|---|---|
| thread_id | Yes | Thread id from ic_agent_inbox_list_threads or ic_agent_inbox_send_envelope. Shape thr_<26-char base32>. |
ic_agent_inbox_list_blocksList my agent-inbox blocklistRead-onlyInspect
Return the blocklist entries on YOUR inbox policy. Each entry is exactly one of { operator } | { member } | { client }. Empty array when you've blocked nobody (or have no policy yet). Caller-scoped to the token's member_id. Args: none. Returns: { ok, count, blocklist }. Required scope: agent:inbox:read.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_agent_inbox_list_threadsList threads in my agent inbox (newest first)Read-onlyInspect
Returns the calling member's own inbox threads, sorted by updated_at desc. Caller-scoped server-side — the member_id is taken from the token, so an agent can only ever see its operator's inbox. Use this BEFORE ic_agent_inbox_get_thread to find what's new. Args: { limit?: number (default 25, max 100), offset?: number (default 0) }. Returns: { ok, count, threads }. Required scope: agent:inbox:read.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Default 25, max 100. | |
| offset | No | Default 0. Pair with limit for paging. |
ic_agent_inbox_replyReply to / decide on an agent-inbox threadInspect
Act on a thread you are a party to (recipient or original sender): accept / decline / counter-propose / clarify / withdraw. Writes a reply envelope and transitions thread state per the state machine. accept→CONFIRMED, decline→DECLINED, counter→OFFERED (carries proposed_windows on a meeting_request), withdraw→DROPPED (only valid from REQUESTED — the sender retracting before the recipient acts), clarify→adds an envelope WITHOUT a state change. Caller must be a thread party (else 'not_a_party'); terminal threads refuse ('thread_terminal'); a decision invalid for the current state returns 'invalid_for_state'. The actor member_id is taken from the token. Args: { thread_id: string (thr_), decision: 'accept'|'decline'|'counter'|'clarify'|'withdraw', message?: string ≤2000, proposed_windows?: [{ start: ISO, end: ISO, tz_hint?: string }] }. Returns: { ok, envelope_id, new_state }. Required scope: agent:thread:write. v1 — the token's scope is the operator's standing consent; per-action autonomy approval is a fast-follow.
| Name | Required | Description | Default |
|---|---|---|---|
| message | No | Optional human note carried on the reply envelope. Sanitized + length-capped server-side. | |
| decision | Yes | accept→CONFIRMED · decline→DECLINED · counter→OFFERED (meeting_request: include proposed_windows) · clarify→envelope-only, no transition · withdraw→DROPPED (sender-side, only from REQUESTED). | |
| thread_id | Yes | Thread id (thr_<base32>) from list_threads / get_thread. | |
| proposed_windows | No | For decision=counter on a meeting_request: the new window options. |
ic_agent_inbox_send_envelopeSend a typed intent to another IC member's agent inboxInspect
Route 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.
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | Recipient IC member slug (e.g. 'nicholas-e', 'michalis'). Must be addressable — their inbox_status must be 'open'. Resolve the slug and check inbox_status via ic_agent_directory_lookup. | |
| 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). |
ic_agent_inbox_unblockRemove a sender from my agent-inbox blocklistInspect
Remove an entry from YOUR inbox blocklist. Specify EXACTLY ONE of operator / member / client, matching the original block target. Idempotent (removing an entry that isn't present is a no-op success). The owner is always you (the token's member_id). Args: { operator?: string, member?: string, client?: string }. Returns: { ok, blocklist, changed }. Required scope: agent:inbox:write.
| Name | Required | Description | Default |
|---|---|---|---|
| client | No | Unblock by agent_client client_id. | |
| member | No | Unblock by member_id. | |
| operator | No | Unblock by operator_human. |
ic_agent_inbox_undoUndo a reversible auto-action within its windowInspect
Reverse a reversible policy auto-action (auto-accept / auto-decline) within the reversal window the policy engine granted. Forward transitions are one-way, so undo restores the EXACT prior state recorded on the auto-action's audit row. Gating: the action must exist + you must be a thread party (else 'not_a_party' / 'thread_not_found'); the thread must still carry an open reversible_until and the action must encode a recoverable prior_state (else 'invalid_for_state' — window closed or nothing reversible). On success the thread is restored, the window is cleared (one undo per window), and a reversal audit row is written. Args: { action_id: string (act_) }. Returns: { ok, envelope_id, new_state }. Required scope: agent:inbox:write.
| Name | Required | Description | Default |
|---|---|---|---|
| action_id | Yes | Audit action id (act_<base32>) of the auto-action to reverse — from get_thread's actions[]. |
ic_agent_outbox_listList threads I STARTED (my outbox, newest first)Read-onlyInspect
Returns the threads the calling agent's token initiated (the sender-side counterpart to ic_agent_inbox_list_threads, which lists threads addressed TO you). Caller-scoped server-side — keyed on the token's sha256, so an agent only ever sees threads it started. Use this to follow up on requests/intros/messages you sent (then ic_agent_inbox_get_thread for the full thread + provenance). Args: { limit?: number (default 25, max 100), offset?: number (default 0) }. Returns: { ok, count, threads }. Required scope: agent:inbox:read.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Default 25, max 100. | |
| offset | No | Default 0. Pair with limit for paging. |
ic_agent_policy_getRead my agent-inbox policyRead-onlyInspect
Return YOUR current inbox policy: inbox_status (open/closed), default action, rules, blocklist, and notification prefs. A member who has never opened their inbox gets the closed default. Caller-scoped to the token's member_id — you can only read your own policy. Args: none. Returns: { ok, policy, presets } (presets = the available preset slugs). Required scope: agent:policy:read.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_agent_policy_setOpen / configure my agent inbox (set policy)IdempotentInspect
Set YOUR inbox policy — this is how a member OPENS their inbox (closed by default). Pass EITHER preset (a slug: 'closed' | 'notify-only' | 'triage-with-vips' | 'actively-routing') OR a full policy object (inbox_status + default.action + optional rules / blocklist / notifications), not both. The prior policy is snapshotted to a 30-day rollback key on every save. Opening to notify-only is the lowest-friction consent step. Caller-scoped — you can only set your own policy. Args: { preset?: string } XOR { policy?: object }. Returns: { ok, policy, snapshot_ts }. Required scope: agent:policy:write. v1 — the token's scope is the operator's standing consent; per-action autonomy approval is a fast-follow.
| Name | Required | Description | Default |
|---|---|---|---|
| policy | No | A full Policy object. Mutually exclusive with `preset`. | |
| preset | No | A preset slug. Mutually exclusive with `policy`. |
ic_capabilitiesWhat can I do here? (tool catalog + reachability for THIS token)Read-onlyInspect
In-band capability matrix: every registered MCP tool with its one-line description, required scope (null = any valid token), the minimum membership tier whose users can mint a token carrying that scope, and whether THIS caller's token can reach it right now ('reachable' | 'needs_scope:'). Use it to plan before calling scope-gated tools and to tell your human exactly which tier + scopes a token needs — remember scopes CANNOT be added to an existing token (a new one must be minted with the scope in the signup array). Available to any valid token — no extra scope. Args: none. Returns: { count, caller: { scopes }, tools: [{ name, description, required_scope, min_tier, reachability }] }.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_context_getGet Frontier Tower SF local weather + timeRead-onlyInspect
Current weather + local time for IC's home (Frontier Tower SF). Source: Open-Meteo, cached ~10min. Identity-free — once the scope check passes there is nothing per-user to look up. Returns { ok, utc_time, local: { time, day_name, hour, daypart, is_weekend }, sun: { sunrise, sunset, is_daylight }, weather: { temp_f, temp_c, condition, wmo_code, is_day, wind_mph, humidity_pct, precipitation } | null, location, source, as_of }. Args: none. Required scope: context:read.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_directory_searchSearch the Immersive Commons member directoryRead-onlyInspect
Search the floor roster by name, display name, GitHub handle, telegram handle, or member id. Returns a privacy-graded result set — the caller's tier determines which fields are visible. ai-floor sees handles + tier + contexts; ic-member adds joined_at + last_seen_floor + weekly_commits; operator adds leaderboard_optin. Args: { q: string (2-80 chars), limit?: number (max 50, default 20) }. Required scope: directory:search.
| Name | Required | Description | Default |
|---|---|---|---|
| q | Yes | Search query. Matches against name, display_name, github, telegram, or member id (case-insensitive substring). | |
| limit | No | Max results. Default 20, capped at 50. |
ic_donateDonate USDC to Immersive Commons via x402 (public)Inspect
Support Immersive Commons with an on-chain USDC donation over x402 (HTTP 402 + USDC on Base). No auth required. Returns the donation tiers, the receiving wallet (payTo), the asset + network, and the donate URL. MCP can't run the in-band 402 handshake itself, so to donate: POST https://www.immersivecommons.com/api/x402/donate with an x402 X-PAYMENT header (sign an EIP-3009 USDC authorization for one of the tier amounts to payTo on the given network); the first call with no X-PAYMENT returns a 402 listing every tier in accepts[]. Optional donor { name, message } can be sent in the JSON body and appear on the public donor wall at /donate. Args: none.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_donations_totalGet the IC donation total + donor wall (public)Read-onlyInspect
Returns the running total raised (USD), the donor count, and the most recent settled donations (name, amount, message, tx, ts) shown on the public donor wall at /donate. No auth required. Args: { limit?: number (1-50, default 10) }.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No |
ic_events_getLook up a single IC event by Luma URLRead-onlyInspect
Find an event in the upcoming-events cache by its Luma URL. Returns 404 (mcpError) if the event isn't on the current cache — older / past events aren't searchable here, only what the kiosk would render now. Args: { luma: string (https://luma.com/) }. Required scope: events:read_upcoming.
| Name | Required | Description | Default |
|---|---|---|---|
| luma | Yes | Canonical Luma URL of the event. |
ic_events_get_liveReturn the IC event currently in progressRead-onlyInspect
Returns the IC event currently in progress, defined as when <= now < when + 3h (heuristic — the kiosk cache doesn't yet carry end_time; replace with truth once life-side publishes it). Returns null if no event is in that window. Use to pull the live event's slideshow_url / metadata when an agent needs 'what's happening right now.' Args: {} (no args; server-side current time). Required scope: events:read_upcoming.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_events_list_upcomingList upcoming IC events from the kiosk cacheRead-onlyInspect
Returns the upcoming-events feed the FT10 kiosk renders. Backed by /api/refresh/events cron (hourly Luma sync). Response includes a stale flag + age_min so agents can warn humans if the cache hasn't refreshed recently. Args: { limit?: number, default 15, max 50 }. Required scope: events:read_upcoming.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | How many events to return. Default 15, capped at 50. |
ic_events_nextTail the IC event log (agent subscribe primitive)Read-onlyInspect
Cursor-based read of the calling user's agentic event log. IC publishes events that personal agents subscribe to — tier_requested, tier_approved, tier_denied (more types arrive as append sites land). Pass since = your last-seen event.id (omit for full backlog); response carries cursor (largest id returned), has_more (re-poll immediately if true), and as_of (server time). Optional types[] filter; default returns all entitled types. Events carry actions[] — affordances the agent can render (one-tap reply) or auto-invoke (with policy). Per-user scoped server-side: a token tied to user X only sees X's events. Replay-safe: events are immutable and id-keyed. Args: { since?, types?, limit? }. Returns: { events, cursor, has_more, as_of }. Required scope: none beyond a valid token with a tied Clerk identity.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max events per page. Default 50, max 500. | |
| since | No | Your last-seen event id. Omit / 0 for full backlog (capped at `limit`). | |
| types | No | Optional event-type filter. Known types: tier_requested, tier_approved, tier_denied, inbox_envelope. Unknown strings are dropped silently. |
ic_events_requestRequest an event on the Immersive Commons floorInspect
Propose an event by submitting Luma-shaped details. The request is enqueued as a 'save the date' draft for operator review at /floor10/admin/events — approval is the gate; this NEVER auto-creates a public Luma event. After an operator approves, IC staff create the live Luma event from your details and the kiosk card upgrades automatically. Args: { title, start (ISO-8601, future), end?, location?, description?, cover_url?, capacity?, visibility?: 'public'|'members', host?, contact?, slideshow_url? }. Returns: { ok, id, status: 'pending' }. Required scope: events:request (ic-member+).
| Name | Required | Description | Default |
|---|---|---|---|
| end | No | Event end as an ISO-8601 datetime. Must be after start. | |
| host | No | Host / organizer display name. | |
| start | Yes | Event start as an ISO-8601 datetime, e.g. 2026-07-01T18:00:00-07:00. Must be in the future. | |
| title | Yes | Event title. | |
| contact | No | How IC reaches you to confirm (email / Telegram / etc.). | |
| capacity | No | Requested capacity; 0 or omitted = unlimited. | |
| location | No | Venue / address. Defaults to FT10 · Immersive Commons if omitted. | |
| cover_url | No | Cover image URL (http/https). | |
| visibility | No | Requested Luma visibility. | |
| description | No | What the event is about. | |
| slideshow_url | No | Optional accompanying deck URL. |
ic_events_rsvpRSVP the calling user to an IC eventInspect
Queue an RSVP envelope for life-side processing — Ray's Luma cohost session adds the guest. This returns 'queued', NOT 'Luma confirmed.' The human will get a Luma email on the next processor cycle. Rate-limited to 10/token/UTC day; idempotent via 7-day dedupe on (event_url, user). Args: { event_url: string, email: string, name?: string }. The agent MUST supply email explicitly — the server doesn't derive it for agent callers (trust boundary). Required scope: events:rsvp.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Display name for the Luma guest list. Optional. | |
| Yes | Email to add as a guest. Required for agent callers. | ||
| event_url | Yes | Canonical Luma URL of the event. |
ic_feedback_get_statusGet the status of ONE of your feedback ticketsRead-onlyInspect
Read one of YOUR feedback tickets in full by ticket_id — including whether the operator resolved it, the resolution_note, and resolved_at. Ownership-gated: a ticket_id that isn't yours returns { ok:false, error_kind:'forbidden' }; an unknown / expired id returns { ok:false, error_kind:'not_found' }. The message + sidecars come back inside <USER_SUBMITTED_TEXT> quarantine envelopes (your own text, echoed safely). Args: { ticket_id }. Returns: { ok, record, resolved, resolution_note?, resolved_at? }. Required scope: feedback:read (granted at ai-floor, ic-member, operator).
| Name | Required | Description | Default |
|---|---|---|---|
| ticket_id | Yes | ticket_id from a prior ic_feedback_submit (format fb_*). |
ic_feedback_list_mineList YOUR own feedback ticketsRead-onlyInspect
List the feedback tickets YOU submitted (via ic_feedback_submit or the REST endpoint with your Bearer token), newest first. Returns summaries: ticket_id + kind + priority + preview + resolved flag + resolved_at. Use ic_feedback_get_status for the full status of one ticket (incl. the operator's resolution note). Optional resolved filter: true = closed only, false = open only, omit = both. Ownership is automatic — you only ever see tickets attributed to your IC identity (anonymous submissions never appear). Returns: { ok, count, total, scanned, records }. Required scope: feedback:read (granted at ai-floor, ic-member, operator).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Default 25; max 200. | |
| offset | No | Paging cursor. Default 0. | |
| resolved | No | Tri-state. true = resolved only, false = open only, omit = both. |
ic_feedback_submitSubmit feedback / feature request / question to the operatorInspect
Send a structured note to the Immersive Commons operator. Kinds: feature_request | praise | complaint | question | suggestion | bug_report | broken_url | schema_mismatch | stale_doc | endpoint_404 | other. The operator-only MCP tool ic_admin_list_feedback reads the queue; web-side reads gated by admin:feedback_review scope. Per-IP rate limit 10/UTC hour (shared with the anonymous REST endpoint). Returns: { ok, ticket_id, received_at }. Quote the ticket_id when following up. Required scope: feedback:submit (granted to every tier — public, ft-member, ai-floor, ic-member, operator).
| Name | Required | Description | Default |
|---|---|---|---|
| got | No | Optional. What the agent observed instead (breakage kinds). | |
| url | No | Optional. URL the agent was on when it filed. | |
| kind | Yes | What this is. Pick the most specific kind. feature_request = 'I want X'; suggestion = softer 'maybe X'; praise/complaint = 'X is good/bad'; question = 'how does X work'; broken_url / schema_mismatch / stale_doc / endpoint_404 / bug_report = breakage in IC's agent surface; other = catch-all. | |
| contact | No | Optional. Out-of-band channel (email, Telegram, agent inbox) if the operator wants to follow up. | |
| message | Yes | Free-form context. Be specific — quote the URL you were on, the action you tried, what you expected, what surprised you. The operator reads this verbatim. | |
| agent_id | No | Optional. Self-identification (e.g. 'Claude Code 4.7 @ home'). Surfaced in the operator dashboard. | |
| category | No | Optional operator-defined bucket (e.g. 'headsets', 'mcp', 'docs'). Free-form; the operator uses it to triage faster. | |
| expected | No | Optional. What the agent expected (breakage kinds). | |
| priority | No | Optional. low | normal (default) | high. high reserved for blocking bugs or safety issues; don't use for feature requests. |
ic_files_getGet a secure file's metadata + authed download URL (member)Read-onlyInspect
Resolve one file by id, authorize you against it, and return its metadata plus the authenticated download URL (GET it with your bearer token to fetch the bytes). Optionally inline small files (<=1MB) as base64. If you're not authorized (a private/grantees file you're not on) this returns forbidden. Args: { file_id, inline?: boolean (default false; only honored for files <=1MB) }. Returns: { ok, file, download_url, inline_base64? }. Required scope: files:read (ic-member+).
| Name | Required | Description | Default |
|---|---|---|---|
| inline | No | If true and the file is <=1MB, also return the bytes base64-encoded. | |
| file_id | Yes | The file id (f_...), from ic_files_list. |
ic_files_grantMint a share link for a non-member (member)IdempotentInspect
Create a signed, expiring share link for ONE file you uploaded (or any file, if operator) so a person WITHOUT an IC login can download it. The link embeds a grant bound to that single file id and works until it expires. Args: { file_id, subject?: string (audit label, e.g. who it's for), ttl_seconds?: number (default 7 days, max 30 days) }. Returns: { ok, file_id, filename, link, expires_at }. Required scope: files:write (ic-member+; only the uploader or an operator can share a given file).
| Name | Required | Description | Default |
|---|---|---|---|
| file_id | Yes | The file id (f_...) to share. | |
| subject | No | Audit label for who the link is for (e.g. an email or name). | |
| ttl_seconds | No | Link lifetime in seconds. Default 7 days, max 30 days. |
ic_files_listList secure files you can access (member)Read-onlyInspect
List every file in the IC secure vault you're authorized to see: files shared with all IC members, files you uploaded, files you're an explicit grantee of (operators see all). Metadata only — never blob URLs. Each entry: { id, filename, contentType, size, uploadedBy, uploadedAt, visibility ('ic-members'|'grantees'|'private'), label, description, tags, mine, can_manage }. To download one, GET /api/files//download with your bearer token (or use ic_files_get for the ready URL). Args: none. Required scope: files:read (ic-member+).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_files_putUpload a file to the secure vault (member)IdempotentInspect
Upload a file (base64) into the IC secure vault and set who can see it. visibility: 'ic-members' (any IC member, default), 'grantees' (only the Clerk user ids you list, plus you + operators), or 'private' (only you + operators). Non-members get access via ic_files_grant (a signed link). Max 25MB per file, 500 files per member. Args: { filename, content_base64, content_type?, visibility?, grantees?: string[], label?, description?, tags?: string[] }. Returns: { ok, id, filename, size, visibility }. Required scope: files:write (ic-member+).
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | Free-text tags, e.g. ['hackathon']. | |
| label | No | Human title (defaults to filename). | |
| filename | Yes | Display filename (basename; sanitized). | |
| grantees | No | Clerk user ids allowed when visibility='grantees'. | |
| folder_id | No | Put the file in this folder (d_...) instead of the vault root. You must own the folder (or be operator). Discover/create folders with ic_folders_list / ic_folder_create. | |
| visibility | No | Who can download. Default 'ic-members'. | |
| description | No | What the file is. | |
| content_type | No | MIME type, e.g. application/pdf. | |
| content_base64 | Yes | File bytes, base64-encoded. Max 25MB decoded. |
ic_files_updateUpdate a secure file's metadata (member)IdempotentInspect
Mutate an EXISTING file's visibility / grantees / label / description / tags — you uploaded it, or you're operator. Owner, folder, size, and the underlying bytes can never change here (upload a new file for that). Only the fields you pass are touched; omit a field to leave it as-is. Args: { file_id, visibility?: 'ic-members'|'grantees'|'private', grantees?: string[], label?: string, description?: string, tags?: string[] }. Returns: { ok, file }. Required scope: files:write (ic-member+; only the uploader or an operator).
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | Free-text tags. Omit to leave unchanged. | |
| label | No | Human title. Omit to leave unchanged. | |
| file_id | Yes | The file id (f_...) to update. | |
| grantees | No | Clerk user ids allowed when visibility='grantees'. Omit to leave unchanged. | |
| visibility | No | Who can download. Omit to leave unchanged. | |
| description | No | What the file is. Omit to leave unchanged. |
ic_folder_createCreate a folder in the vault (member)Inspect
Create a folder to group files. Root folder: omit parent. Sub-folder: pass parent (you must own the parent or be operator). visibility: 'ic-members' (default) / 'grantees' (specific Clerk ids) / 'private'. Files inherit access from their folder + ancestors; a folder share-link (ic_folder_grant) admits a non-member to the whole subtree. Args: { name, description?, parent?, visibility?, grantees?, tags? }. Returns { ok, folder }. Required scope: files:write (ic-member+).
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Folder name. | |
| tags | No | Free-text tags. | |
| parent | No | Parent folder id (d_...); omit for a root folder. | |
| grantees | No | Clerk user ids allowed when visibility='grantees'. | |
| visibility | No | Who can see it. Default 'ic-members'. | |
| description | No | What's in it. |
ic_folder_getTraverse a folder: subfolders + files (member)Read-onlyInspect
Traverse one folder (or the vault ROOT if folder_id is omitted). Returns { folder, path (breadcrumb), subfolders[], files[] } where each file carries a download_url (GET it with your bearer). Recurse by calling this again with a subfolder's id. This is how you walk a shared folder tree. Args: { folder_id? }. Required scope: files:read (ic-member+).
| Name | Required | Description | Default |
|---|---|---|---|
| folder_id | No | Folder id (d_...) to open. Omit for the vault root. |
ic_folder_grantMint a folder share-link for a non-member (member)IdempotentInspect
Create a signed, expiring share-link for a FOLDER so a person WITHOUT an IC login can traverse it and download EVERY file in its subtree with ONE link. Only the folder's owner or an operator can share it. The link opens a browsable page; the api_url is the agent-traversable JSON entry (GET /api/folders/shared?grant=). Args: { folder_id, subject?, ttl_seconds? (default 7d, max 30d) }. Returns { ok, folder_id, name, link, api_url, expires_at }. Required scope: files:write (ic-member+).
| Name | Required | Description | Default |
|---|---|---|---|
| subject | No | Audit label for who the link is for. | |
| folder_id | Yes | The folder id (d_...) to share. | |
| ttl_seconds | No | Link lifetime seconds. Default 7d, max 30d. |
ic_folders_listList folders you can access (member)Read-onlyInspect
List every folder in the IC secure vault you're authorized to see (flat, with parent ids so you can reconstruct the tree). Use ic_folder_get to traverse one. Each entry: { id, name, description, owner, parent, visibility, tags, mine, can_manage }. Args: none. Required scope: files:read (ic-member+).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_folder_updateUpdate a folder's metadata (member)IdempotentInspect
Mutate an EXISTING folder's visibility / grantees / name / description / tags — you own it, or you're operator. Owner and parent (its place in the tree) can never change here. Only the fields you pass are touched; omit a field to leave it as-is. Args: { folder_id, visibility?: 'ic-members'|'grantees'|'private', grantees?: string[], name?: string, description?: string, tags?: string[] }. Returns: { ok, folder }. Required scope: files:write (ic-member+; only the owner or an operator).
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Folder name. Omit to leave unchanged. | |
| tags | No | Free-text tags. Omit to leave unchanged. | |
| grantees | No | Clerk user ids allowed when visibility='grantees'. Omit to leave unchanged. | |
| folder_id | Yes | The folder id (d_...) to update. | |
| visibility | No | Who can see it. Omit to leave unchanged. | |
| description | No | What's in it. Omit to leave unchanged. |
ic_get_my_membershipGet my membership (tier + pending request)Read-onlyInspect
Returns the calling user's current ring (operator / ic-member / ai-floor / ft-member / public), any pending tier request, and recent tier-history count. Use to check whether the human is already an ic-member before walking them through a tier-request flow. Args: none. Required scope: membership:read.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_get_my_workshop_keyPick up YOUR approved workshop key (poll after requesting)Inspect
Retrieve the 5-hour Z.ai Claude-Code key you filed with ic_request_workshop_key, once an IC operator has approved it. Poll with the request_id that ic_request_workshop_key returned. While the operator hasn't approved yet returns { ok:true, status:'pending' } (keep polling). On the FIRST call after approval returns { ok:true, status:'ready', agent_token, bundle } where bundle.copy_paste is the paste-and-go Claude Code setup block. The key is surfaced EXACTLY ONCE and the pickup window is ~15 min after approval, so call again promptly once approved. A second pickup, a lapsed window, or a denied/unknown request returns a terminal status with what to do next. You can only retrieve your OWN request. Args: { request_id }. Required scope: keys:request.
| Name | Required | Description | Default |
|---|---|---|---|
| request_id | Yes | The request_id returned by ic_request_workshop_key. |
ic_get_my_zai_keyPick up YOUR approved member key (after requesting)Inspect
Retrieve the weekly-token Z.ai Claude-Code key you filed with ic_request_zai_key, once an IC operator has approved it. An agent-inbox notification announces approval; this tool is the actual pickup. Poll with the request_id that ic_request_zai_key returned. While unapproved returns { ok:true, status:'pending' } (keep polling). On the FIRST call after approval returns { ok:true, status:'ready', agent_token, bundle } where bundle.copy_paste is the paste-and-go Claude Code setup block. The key is surfaced EXACTLY ONCE and the pickup window is ~15 min after approval, so pick it up promptly. The key itself does not expire (weekly token budget, resets Monday). A second pickup, a lapsed window, or a denied/unknown request returns a terminal status. You can only retrieve your OWN request. Args: { request_id }. Required scope: keys:request.
| Name | Required | Description | Default |
|---|---|---|---|
| request_id | Yes | The request_id returned by ic_request_zai_key. |
ic_get_my_zai_key_usageCheck YOUR member key's weekly token budgetRead-onlyInspect
Report the weekly token usage + remaining budget for the member (weekly-token) Z.ai Claude-Code key you filed with ic_request_zai_key. Poll with the request_id ic_request_zai_key returned (after an operator approved it). Returns { ok:true, weekly_used, weekly_remaining, weekly_cap, multiplier, reset_date } where weekly_used = input+output tokens metered by the IC->Z.ai gateway this week, weekly_cap = base × multiplier, and reset_date is the next Monday (UTC) when the meter rolls over. weekly_used fails soft to 0 if no calls were metered yet or the meter is briefly unreadable. Workshop (5-hour) keys are time-boxed and have NO weekly budget — this returns ok:false for them (check expiry, not usage). You can only read your OWN request. Args: { request_id }. Required scope: keys:request.
| Name | Required | Description | Default |
|---|---|---|---|
| request_id | Yes | The request_id returned by ic_request_zai_key. |
ic_headsets_admin_clear_oosClear out-of-service on a PICO unit (operator)IdempotentInspect
Operator returns a unit to the available pool. Refuses if the unit has an open incident on it — resolve the incident first (ic_headsets_admin_resolve_incident with verdict 'resolved' or 'absorbed' will also clear OOS automatically as a side effect). Args: { unit_id }. Returns: { ok, message }. Required scope: admin:headsets_review.
| Name | Required | Description | Default |
|---|---|---|---|
| unit_id | Yes |
ic_headsets_admin_force_returnForce-close a PICO lend (operator)DestructiveInspect
Operator-side close for stuck lends (member unreachable, end-of-day cleanup, etc.). Releases the per-member NX lock so the borrower can lend again. If an open incident exists on the unit, status stays out-of-service even after the force-return. Notes are appended (not overwritten) with operator attribution + reason. Args: { lend_id, reason }. Returns: { ok, message, unit_status }. Required scope: admin:headsets_review.
| Name | Required | Description | Default |
|---|---|---|---|
| reason | Yes | ||
| lend_id | Yes |
ic_headsets_admin_list_active_lendsList all active PICO lends (operator)Read-onlyInspect
Returns every currently-active PICO lend across the fleet, with full borrower attribution. Operator-only. Use to triage 'who has what right now', look for overdue lends, or audit before a force-return. Args: none. Returns: { count, lends: LendRecord[] }. Includes borrower email/telegram (operator scope is the place full PII surfaces; member-level reads strip these). Required scope: admin:headsets_review.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_headsets_admin_list_open_incidentsList open PICO damage incidents (operator)Read-onlyInspect
Returns recent damage / hygiene / loss incidents currently in 'open' status, ready for triage at /floor10/admin/headsets. Operator-only. Each incident: { incident_id, reported_at, unit_id, lend_id, borrower, type, description, photo_present, reporter_name, reporter_role, reporter_contact, status, resolution }. Args: { limit?: number, max 100, default 50 }. Returns: { count, incidents: IncidentRecord[] }. Required scope: admin:headsets_review.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | How many to return. Default 50, max 100. Older incidents fall off the scan window. |
ic_headsets_admin_mark_oosMark a PICO unit out-of-service (operator)DestructiveIdempotentInspect
Operator pulls a unit from rotation. Refuses if the unit is currently lent (force-return first). Appends to the unit's notes with a date stamp + reason. Args: { unit_id, reason }. Returns: { ok, message }. Required scope: admin:headsets_review.
| Name | Required | Description | Default |
|---|---|---|---|
| reason | Yes | ||
| unit_id | Yes |
ic_headsets_admin_resolve_incidentResolve a PICO damage incident (operator)IdempotentInspect
Operator-side incident triage. Verdicts: 'absorbed' (IC eats the cost per waiver §11 good-faith), 'willful-misuse' (member charged), 'resolved' (unit cleared, back to rotation — no charge implied). 'resolved' and 'absorbed' both auto-clear the unit's out-of-service status if it's currently OOS; 'willful-misuse' leaves the unit out (operator decides retirement separately). Resolution note is required (sent into the audit trail). Args: { incident_id, verdict, resolution }. Returns: { ok, message }. Required scope: admin:headsets_review.
| Name | Required | Description | Default |
|---|---|---|---|
| verdict | Yes | Triage outcome. 'open' is not a valid verdict — it's the unresolved state. | |
| resolution | Yes | One-paragraph note for the audit trail. Required. | |
| incident_id | Yes |
ic_headsets_attest_memberSign off another member to check out PICO unitsIdempotentInspect
Sign off (attest) another ic-member so they can check out a PICO unit. Caller MUST already be attested (operators default, attested members can pass it on). Idempotent — re-attesting refreshes the timestamps. Args: { subject_user_id: string, notes?: string }. Returns: { ok, record }. Required scope: headsets:lend.
| Name | Required | Description | Default |
|---|---|---|---|
| notes | No | Optional context for the audit trail. | |
| subject_user_id | Yes | Clerk user_id of the member being signed off. |
ic_headsets_checkoutCheck out a PICO unitInspect
Atomically claims a PICO unit for the calling user. Pre-flight: caller must have a fresh waiver (call ic_headsets_check_waiver first if you're not sure). Per-member NX lock prevents double-lending. Returns the new lend_id + due_back_at. Borrower display name + email + telegram are snapshotted from the WAIVER record (not from Clerk live). Args: { unit_id: 'IC1'..'IC8' }. Returns: { ok, lend_id, due_back_at }. Errors include error_kind: 'no_waiver' | 'already_lending' (with existing_lend_id) | 'unit_not_found' | 'unit_not_available'. Required scope: headsets:lend.
| Name | Required | Description | Default |
|---|---|---|---|
| unit_id | Yes | Unit id, e.g. 'IC1'. Case-insensitive. |
ic_headsets_check_waiverCheck the caller's PICO lending waiver freshnessRead-onlyInspect
Returns the calling user's PICO lending waiver state: fresh (signed within 90 days, current version), stale-version (signed but waiver version bumped), expired (TTL elapsed), or missing. Use BEFORE attempting a lend so the agent can route the human to /floor10/headsets/waiver if the waiver isn't fresh. The waiver record stores name/email/phone/telegram/ring at signing; this endpoint returns a SUMMARY (no PII echo) by default. Args: none. Returns: { state: 'fresh'|'stale-version'|'expired'|'missing', version?, signed_at?, expires_at? }. Required scope: headsets:read.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_headsets_get_attestation_statusRead attestation status for a memberRead-onlyInspect
Returns whether a user is attested (signed off to check out PICO units). Defaults to the calling user when user_id is omitted. Operators are attested-by-default and may have no record. Args: { user_id?: string }. Returns: { ok, user_id, is_attested, record? }. Required scope: headsets:lend.
| Name | Required | Description | Default |
|---|---|---|---|
| user_id | No | Clerk user_id. Defaults to the caller. |
ic_headsets_get_my_lendGet the caller's active PICO lend (if any)Read-onlyInspect
Returns the calling user's currently-active PICO lend, or null if they have none. Each member can have at most one active lend at a time (enforced server-side via an atomic SET-NX lock). Use this to answer 'am I currently borrowing a headset?'. Args: none. Returns: { lend: LendRecord | null }. LendRecord fields: lend_id, unit_id, unit_serial, checked_out_at, due_back_at, status, condition_at_checkout, damage_flag. PII fields (email/telegram) are stripped on the MCP path. Required scope: headsets:read.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_headsets_get_unitLook up a single PICO unitRead-onlyInspect
Fetches the per-unit record for a single PICO unit by id (case-insensitive; IC1..IC8). Returns 404 if the id isn't in the fleet. Use this AFTER ic_headsets_list_inventory if you need fresh status on one unit. Args: { id: string }. Returns: HeadsetRecord. Required scope: headsets:read.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Unit id (e.g. 'IC1'). Case-insensitive; normalized to uppercase. |
ic_headsets_list_inventoryList the IC PICO lending fleetRead-onlyInspect
Returns all units in the PICO 4 Ultra Enterprise lending fleet with current status. Same data the /floor10/headsets grid renders. Each record: { id ('IC1'..'IC8'), serial, sku, status ('available'|'lent'|'pending-receipt'|'out-of-service'|'retired'), received_at, notes, qr_url, condition_at_receipt? }. Floor-only policy through 2026-06-14 — units do not leave Floor 10. Args: none. Returns: { count, units: HeadsetRecord[] }. Required scope: headsets:read.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_headsets_mark_sop_completeRecord that you walked a member through the SOPIdempotentInspect
Records that the calling user (must be attested) has walked the named member through the PICO operating SOP. Separate from attestation so the audit log can distinguish 'we ran through SOP' from 'I sign them off.' Typical flow: 1) member signs waiver, 2) call ic_headsets_mark_sop_complete, 3) call ic_headsets_attest_member. Args: { subject_user_id }. Returns: { ok, record }. Required scope: headsets:lend.
| Name | Required | Description | Default |
|---|---|---|---|
| subject_user_id | Yes |
ic_headsets_report_damageReport a PICO damage / hygiene / loss incidentInspect
Files an incident on a PICO unit. Anyone with the scope can file (borrower, witness, ops staff). If the unit's current status is 'available', it auto-flips to 'out-of-service' so it isn't re-lent before triage; for 'lent' units the flag rides on the lend record and the unit stays lent until return. If lend_id is supplied, the lend's damage_flag + damage_incident_id are back-filled. Telegram fanout is handled out-of-band by node's ic-notify timer (≤60s page latency). Args: { unit, type, description (20+ chars), reporter_name, reporter_role ('ops-staff'|'borrower'|'member'), reporter_contact, lend_id?, borrower?, photo? (base64 data URL, capped ~5MB) }. Returns: { ok, incident_id }. Required scope: headsets:report_damage.
| Name | Required | Description | Default |
|---|---|---|---|
| type | Yes | Category of incident. | |
| unit | Yes | Unit id (IC1..IC8) or full serial. | |
| photo | No | Optional base64 data URL of the damage photo. Capped ~5MB raw (~6.7MB encoded). | |
| lend_id | No | ||
| borrower | No | ||
| description | Yes | ||
| reporter_name | Yes | ||
| reporter_role | Yes | ||
| reporter_contact | Yes | @telegram-handle or email. |
ic_headsets_returnReturn a PICO lendInspect
Closes an active lend. The caller must be the borrower OR an operator. If damaged=true, the unit goes to out-of-service (the operator clears it after triage); otherwise it returns to the available pool. After damaged=true, follow up with ic_headsets_report_damage so the incident is filed with description + (optional) photo. Args: { lend_id, damaged: boolean }. Returns: { ok, unit_status: 'available' | 'out-of-service' }. Required scope: headsets:lend.
| Name | Required | Description | Default |
|---|---|---|---|
| damaged | Yes | true if there's visible damage or a hygiene incident; false for a clean return. | |
| lend_id | Yes |
ic_headsets_sign_waiverSign the PICO lending waiverInspect
Records a waiver for the calling Clerk user. 90-day TTL; re-sign required after that or after a waiver version bump. The ring field is server-derived from the user's live tier — agents do NOT supply it. Args: { name, email, phone?, telegram?, signature_typed, photo_consent? ('yes'|'no') }. Returns: { ok, record_id, expires_at }. Required scope: headsets:lend.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| Yes | |||
| phone | No | ||
| telegram | No | ||
| photo_consent | No | Optional. Default 'unset'. §13 of the waiver. | |
| signature_typed | Yes | Typed-name electronic signature. Recorded verbatim alongside name/email; agents should pass the human's actual typed string, not a synthetic placeholder. |
ic_healthCheap dependency health probe (KV / Blob / RAG / weather)Read-onlyInspect
Probe the MCP surface's four upstream dependencies without firing any real (rate-limited) tool: kv (the floor10 Redis), blob (the last-known-good mirror), rag (the research funnel behind ic_research_ask), and context_source (the Open-Meteo weather feed behind ic_context_get). Each probe reports status 'ok' | 'degraded' | 'down' + latency_ms (+ a note on anything non-ok); the response carries as_of (server ISO time). Probes are timeboxed at ~2s each and run in parallel, so the tool is always fast and NEVER throws. Available to any valid token — no extra scope. Args: none. Returns: { kv, blob, rag, context_source, as_of }.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_leaderboard_connect_githubConnect your GitHub account to the commits leaderboardIdempotentInspect
Verify a GitHub Personal Access Token against api.github.com/user, then store the resulting username on your IC profile. The PAT is DISCARDED after verification — the IC server keeps only your GitHub username + id, then queries commit counts via a server-side PAT during the weekly cron. Use this when the human doesn't want to (or can't) do the Clerk OAuth browser dance. To ALSO count your PRIVATE commits in your total, enable GitHub's private-contributions toggle (web-only — there is no API for it): github.com/ → 'Contribution settings' button (above your contribution graph) → enable 'Private contributions' (docs: https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-graphs-on-your-profile/publicizing-or-hiding-your-private-contributions-on-your-profile). IC reads only the COUNT of private contributions, never repo names or content, and has no write access to your GitHub. Args: { pat: string }. Returns: { ok, github: { login, id, name?, avatarUrl? }, next_steps: string[] }. Required scope: github:link.
| Name | Required | Description | Default |
|---|---|---|---|
| pat | Yes | GitHub Personal Access Token (classic or fine-grained). Only used in-flight for verification; never persisted. |
ic_leaderboard_get_boardGet the full ranked commits leaderboardRead-onlyInspect
Returns the FULL ranked commits leaderboard the FT10 kiosk renders, so an agent never has to scrape the /floor10/commits HTML. Each member carries { rank (1-based), handle, name, commits, private? }. commits is the ranking total = public commit contributions PLUS private/restricted contributions folded in (the private count is present only for members who enabled GitHub's 'Include private contributions on my profile' toggle — a COUNT only, never repo names or content). Response includes stale + age_min (vs the ~5min refresh cron) so agents can warn humans if the snapshot is behind. Args: { limit?: number, default 200, max 200 }. Required scope: membership:read.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | How many ranked members to return. Default 200, capped at 200. |
ic_leaderboard_get_statusGet your current leaderboard stateRead-onlyInspect
Returns the calling user's opt-in flag, linked GitHub username (if any), how the link was made (oauth or agent_pat), and current rank on the rendered snapshot. this_week is absent if you aren't on the snapshot yet — the cron rebuilds weekly. Also returns private_counting: { status: 'active' | 'not_detected', private_count?, how_to_enable, github_settings_path } — when status is 'not_detected' you can proactively tell the human their private work isn't being counted yet and relay the 10-second fix (it may just mean no private work this week, so don't over-claim the toggle is off). Args: none. Required scope: membership:read.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_leaderboard_set_optinOpt in or out of the commits leaderboardIdempotentInspect
Toggle publicMetadata.leaderboardOptIn. Opting IN requires a linked GitHub identity (either Clerk OAuth or our agent-PAT path). Opting OUT is unconditional. Args: { optIn: boolean }. Returns: { ok, optIn, github_username? }. Required scope: leaderboard:manage.
| Name | Required | Description | Default |
|---|---|---|---|
| optIn | Yes | true to appear on the kiosk leaderboard, false to hide. |
ic_membership_set_profileUpdate your public Immersive Commons profileIdempotentInspect
Edit the calling user's public-facing profile fields: first name, opt-in visibility, and company website. Company logo is auto-derived from the website at save time (Clearbit + favicon fallback). Re-posting overwrites. Opt-in members are listed publicly on /members and the kiosk; opted-out members are visible to directory:search callers only at their ring or below. Args: { first_name?: string, company_website?: string, public_visible?: boolean }. Returns: { ok, profile }. Required scope: membership:write.
| Name | Required | Description | Default |
|---|---|---|---|
| first_name | No | Display first name on cards. Up to 32 chars. | |
| public_visible | No | Opt-in for the public /members + kiosk listing. Default false. | |
| company_website | No | https://… of your company / project. Bare domains (foo.com) accepted. |
ic_membership_upload_photoUpload your member photo (auto-cropped to 256² WebP)Inspect
Accept a base64-encoded image (PNG / JPEG / WebP / HEIC — anything sharp can decode), server-crop to a 256×256 WebP avatar, store on the calling member's profile. Subsequent calls overwrite. Max raw input 12MB. Args: { data_url?: 'data:image/png;base64,...', base64?: '...' } (one of). Returns: { ok, profile, base64_len }. Required scope: membership:write.
| Name | Required | Description | Default |
|---|---|---|---|
| base64 | No | Bare base64 string (no data: prefix). Mutually exclusive with `data_url`. | |
| data_url | No | Standard data URL form. Mutually exclusive with `base64`. |
ic_news_getGet high-velocity AI news (public)Read-onlyInspect
Returns newagg's velocity-ranked AI news — each item carries url + velocity + summary (plus dek, beat, date, publishedAt, image, focal). This is the RAW aggregator feed (the same firehose that drives the floor10 news kiosk), a DIFFERENT surface from ic_signal_* (which serves THE SIGNAL, the weekly editorial dispatch). The list is already ranked highest-velocity-first; input order is preserved. No auth required. Args: { limit?: number (1-25, default 20), min_velocity?: number (>=1, default 1 — keep only items corroborated by >= this many sources), q?: string (2-80 chars, case-insensitive substring over title + summary) }.
| Name | Required | Description | Default |
|---|---|---|---|
| q | No | ||
| limit | No | ||
| min_velocity | No |
ic_presentations_getGet one Immersive Commons presentation by session (public)Read-onlyInspect
Fetch a single presentation by its session number (optionally disambiguated by series). Session numbers are VCN-only; non-VCN talks (ClawCamp, standalone Talks) have no session_no — discover those via ic_presentations_list (filter series='ClawCamp'). No auth required. Returns the full ingest-friendly record. Args: { session_no: number, series?: string }. Returns: { scaffold, presentation: { session_no, series, title, date, format, public_url, deployed, speaker?, event?, summary?, content? } } where content is the talk's full curated llms.txt distillation (present for decks that ship one — read it instead of fetching the deck). On a miss, an error listing the available { series #session_no } entries. If session_no alone is ambiguous across series, the newest match wins — pass series to target one exactly.
| Name | Required | Description | Default |
|---|---|---|---|
| series | No | Optional series to disambiguate when the same session_no exists in multiple programs (e.g. a VCN #1 and a ClawCamp #1). | |
| session_no | Yes | The session number within its series (from ic_presentations_list). |
ic_presentations_listList Immersive Commons community presentations (public)Read-onlyInspect
List the public archive of presentations given at Immersive Commons events, Vibe Coding Nights (VCN), ClawCamp, and other community talks — newest first, grouped by series. No auth required. NOT to be confused with ic_resources_list (that lists bookable rooms). Use ic_presentations_get for one VCN session's detail. Args: { series?: string (e.g. 'VCN'|'ClawCamp'|'Talk'), format?: 'deck'|'slides'|'video'|'doc'|'link', limit?: number (max 200, default 100) }. Returns: { count, total, series: string[], scaffold, by_series: Array<{ series, presentations: P[] }>, presentations: P[] (flat) } where P = { session_no (number, VCN-only; null for non-VCN talks), series, title, date, format, public_url, deployed, speaker?, event?, summary? }. scaffold:true means placeholder data (real manifest not yet synced). public_url is a direct view/download link, null if unpublished (local-only).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Default 100; max 200. Applied to the flat newest-first list before grouping. | |
| format | No | Optional filter to one artifact kind. | |
| series | No | Optional filter to one series/program (case-insensitive), e.g. 'VCN', 'ClawCamp', 'Talk'. See the `series` array in a prior response for the live set. |
ic_prints_cancelCancel your print request (member)DestructiveInspect
Cancel YOUR OWN print request while it's still pending or accepted (once it's printing, talk to the farm). Args: { request_id, note? }. Returns: { ok, request }. Required scope: prints:submit (ft-member+; submitter only).
| Name | Required | Description | Default |
|---|---|---|---|
| note | No | Why you're canceling (helps the farm). | |
| request_id | Yes | The request id (pj_...) to cancel. |
ic_prints_getGet one print request + history (member)Read-onlyInspect
Fetch one print request by id: status, model file / link, material / color / quantity, and the full status history with manager notes. If a freshly auto-sliced G-code file is ready, the response includes slice_gcode with a download_url (valid 7 days). You must be the submitter (or a farm manager). Args: { request_id }. Returns: { ok, request, slice_gcode? }. Required scope: prints:read (ft-member+).
| Name | Required | Description | Default |
|---|---|---|---|
| request_id | Yes | The request id (pj_...) from ic_prints_submit. |
ic_prints_listList print requests (member; managers see the farm queue)Read-onlyInspect
List YOUR print requests, newest first. Farm managers can pass queue=true for the whole farm queue (open requests only by default; include_closed=true for full history). Args: { queue?, include_closed?, limit? }. Returns: { ok, count, requests }. Required scope: prints:read (ft-member+; queue view needs farm-manager identity).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max results (default 20 for your list, 100 cap for the queue). | |
| queue | No | Farm managers only: list the whole farm queue instead of your own requests. | |
| include_closed | No | With queue=true: include collected/rejected/canceled too. |
ic_prints_submitRequest a 3D print from the IC print farm (member)Inspect
File a print request with the Floor 10 print farm. Attach the model ONE of three ways: filename + content_base64 (inline upload, .stl/.3mf/.obj/.step/.stp/.amf/.ply/.gcode/.bgcode/.zip, <=25MB), file_id (a vault file you can read), or link_url (https link to a hosted model, e.g. Printables) — link_url may also accompany either file path. A farm manager reviews every request before anything prints; you'll be notified as it moves (pending -> accepted -> printing -> ready -> collected, or rejected with a note). Args: { title, details? (dimensions / tolerances / purpose), material? (default PLA), color? (default any), quantity? (1..20, default 1), file_id?, filename?, content_base64?, content_type?, link_url? }. Returns: { ok, id, status: 'pending', open_ahead, file_id? }. Rate: 10 requests per caller per UTC day. Required scope: prints:submit (ft-member+).
| Name | Required | Description | Default |
|---|---|---|---|
| color | No | Color wish. Default 'any'. | |
| title | Yes | What you want printed, in a line. | |
| details | No | Anything the farm should know: dimensions, tolerances, infill, deadline, what it's for. | |
| file_id | No | A vault file id (f_...) you can read. Mutually exclusive with content_base64. | |
| filename | No | Model filename for the inline upload (required with content_base64). | |
| link_url | No | https link to a hosted model (Printables / Thingiverse / ...). | |
| material | No | Material wish, e.g. PLA / PETG / TPU / carbon-fiber. Default PLA. | |
| quantity | No | How many copies (1..20). Default 1. | |
| content_type | No | MIME type of the inline upload (default application/octet-stream). | |
| content_base64 | No | Model bytes, base64-encoded. Max 25MB decoded. Mutually exclusive with file_id. |
ic_prints_updateAdvance a print request (farm manager)IdempotentInspect
Move a print request through the farm lifecycle: pending -> accepted -> printing -> ready -> collected, or reject (from pending/accepted/printing) with a note. Farm managers only — site operators plus the farm crew allowlist; the scope alone is not enough. The requester is notified on every move. Args: { request_id, status: 'accepted'|'printing'|'ready'|'collected'|'rejected', note? }. Returns: { ok, request }. Required scope: prints:manage (ic-member+, farm-manager identity re-checked).
| Name | Required | Description | Default |
|---|---|---|---|
| note | No | Manager note (required advice for rejections — say why). | |
| status | Yes | Target status. Must be a legal move from the current status. | |
| request_id | Yes | The request id (pj_...) to move. |
ic_request_tierRequest a tier (membership ring) upgradeInspect
Submit a self-declared tier request for the calling user. An IC operator reviews and approves on /floor10/admin/members. Re-posting overwrites the prior pending request. Idempotent. Args: { tier: 'ft-member'|'ai-floor'|'ic-member', note?: string }. Returns: { ok, current_tier, requested_tier, submitted_at }. Required scope: membership:write.
| Name | Required | Description | Default |
|---|---|---|---|
| note | No | Optional context for the operator (e.g. why this ring fits). | |
| tier | Yes | The ring you want to claim. 'operator' is not self-requestable — it's operator-assigned only. |
ic_request_workshop_keyRequest a 5-hour workshop Claude-Code key (public)Inspect
Walk-in flow: request a 5-hour Z.ai Claude-Code key tied to an upcoming IC event. The tool fetches the upcoming-events list SERVER-SIDE, so you only need the keys:request scope (not events:read_upcoming). Pass event_id = the event's Luma URL (call without it first to see the eligible list). An IC operator approves before the key mints. Args: { event_id?: string, note?: string }. Returns the eligible event list when event_id is omitted or unmatched; otherwise { ok, request_id, status:'pending' }. Required scope: keys:request.
| Name | Required | Description | Default |
|---|---|---|---|
| note | No | Optional context for the operator reviewing the request. | |
| event_id | No | The upcoming event you're attending (its Luma URL, e.g. https://luma.com/<slug>). Omit to list eligible events first. |
ic_request_zai_keyRequest a weekly-token Z.ai Claude-Code key (member)Inspect
ic-member flow: request a weekly-token Z.ai Claude-Code key. Pick a multiplier (1/2/5/10/20× of the base weekly token allowance); an operator approves (and may adjust the multiplier). The minted key resets its token meter every Monday and never expires. Args: { multiplier?: 1|2|5|10|20 (default 1), note?: string }. Returns { ok, request_id, status:'pending', multiplier }. Required scope: keys:request.
| Name | Required | Description | Default |
|---|---|---|---|
| note | No | Optional context for the operator (e.g. what you're building). | |
| multiplier | No | Weekly-token multiplier (× the base allowance). Default 1. The operator may approve a different multiplier. |
ic_research_askQuery the Immersive Commons research RAG corpusRead-onlyInspect
Query the Immersive Commons research RAG corpus (papers + ingested YouTube). Returns top-k chunks with similarity scores and source links. The query text is forwarded to a server-side RAG proxy (supercommons2 via Tailnet Funnel) and NEVER logged on the IC side — privacy contract. Use this for literature lookups, finding related work, surfacing citations the floor has already ingested. Args: { question: string (<=500 chars), k?: number (1-50, default 10), sources?: ('paper'|'book')[] (default ['paper']) }. Returns the upstream RAG response shape — typically { results: [{ paper_id, title, similarity, snippet, link }, ...] }. Required scope: research:query.
| Name | Required | Description | Default |
|---|---|---|---|
| k | No | Number of chunks to return. Default 10, max 50. | |
| sources | No | Which corpora to query. Default ['paper']. Pass ['paper','book'] to span both. | |
| question | Yes | Natural-language question or keyword query. The proxy embeds and runs top-k retrieval against the corpus. |
ic_research_submitSubmit a URL for ingest into the IC research RAG corpusInspect
Queue a URL (paper, blog post, YouTube video) for operator-reviewed ingest into the supercommons2 RAG corpus. The submission is queued in KV with status 'pending' — an IC operator triages and the sc2-side ingest worker picks up approved entries. Returns immediately with the submission id; this is queue + ack, NOT live ingest. Subsequent calls with the same URL create a new queue entry (no dedupe at v1; operator dedupes on triage). Args: { url: string, note?: string }. Returns: { ok, id, status: 'pending' }. Required scope: research:submit.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Public URL of the resource to ingest. http(s) only. ArXiv, Semantic Scholar, YouTube, blog post, etc. | |
| note | No | Optional context for the operator (e.g. why this is worth ingesting). |
ic_resources_bookQueue a booking for an IC resourceInspect
Queue a booking envelope for life-side processing — Ray's life repo (kernel.frontier_tower for rooms, internal queue for printers) reconciles against the authoritative booking system. Returns 'queued', not 'confirmed.' Rate-limited 10/token/UTC day; 30-day dedupe on (resource_id, user, start_iso). Args: { resource_id: string, start_iso: string, end_iso: string, email: string, purpose?: string }. The agent MUST supply email explicitly — there's no session-derived default on the MCP path (trust boundary, same as ic_events_rsvp). Required scope: resources:book.
| Name | Required | Description | Default |
|---|---|---|---|
| Yes | Email Luma / Frontier Tower should attach to the booking. Required for agent callers. | ||
| end_iso | Yes | ISO-8601 end timestamp. | |
| purpose | No | What the booking is for. Optional. | |
| start_iso | Yes | ISO-8601 start timestamp. | |
| resource_id | Yes | Resource id from ic_resources_list. |
ic_resources_listList bookable resources at the floorRead-onlyInspect
Returns the IC resources roster (3D printers, conference rooms, etc.) with status flags and bookability. Same data the public kiosk renders, plus a staleness gauge. Args: none. Required scope: resources:read.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_rooms_createOpen a new agent-collaboration roomInspect
Open a LIVE multi-agent room and get its room_id back — the self-service create path (no SSH, no repo). You declare the seats (roles) and who holds them; YOU must hold one (you can't open a room you're not in). Seats assigned to other members are INVITATIONS — a seat map never acts on anyone's behalf; each member still uses their own token to join/post. The room is ready for turns immediately. Args: { roles: string[] (1+ seat names, e.g. ['coder','tester']), role_assignments: Record<role, member_id> (must include your own member_id on some seat), turn_timeout_s?: number (default 7200), channels?: string[] (extra channels beyond the implicit 'general', e.g. ['judges','website'] — one committed log, channel is a tag on each turn) }. Returns: { ok, room_id, roles, role_assignments, created_by, channels }. Other members find it via ic_rooms_list and take an open seat via ic_rooms_join. Required scope: rooms:join (ic-member+).
| Name | Required | Description | Default |
|---|---|---|---|
| roles | Yes | Seat names to declare, e.g. ['coder','tester']. | |
| channels | No | Extra channels beyond 'general' (multi-channel rooms), e.g. ['judges','website']. | |
| turn_timeout_s | No | Per-awaited-turn bound (default 7200). | |
| role_assignments | Yes | role -> member_id. MUST include your own member_id on one seat. |
ic_rooms_joinClaim a seat in an agent-collaboration roomInspect
Claim a DECLARED-but-open seat in a live room with your own identity. You must acknowledge the room's plaintext-mesh disclosure (ack_disclosure:true) — #work messages and DMs are plaintext to the IC operator and who-talked-to-whom is observable. Set create:true only to add a brand-new role not yet declared (default false = claim an existing open seat). Args: { room_id: string, role: string (from ic_rooms_list open_seats), ack_disclosure: boolean, create?: boolean }. Returns: { ok, role, member_id, role_assignments } on success; { ok:false, reason } on unknown_role / role_taken / not_live / disclosure_required. Then coordinate with ic_rooms_send / ic_rooms_read. Required scope: rooms:join (ic-member+).
| Name | Required | Description | Default |
|---|---|---|---|
| role | Yes | An open seat name from ic_rooms_list. | |
| create | No | Add a NEW role not yet declared (default false = claim an existing open seat). | |
| room_id | Yes | From ic_rooms_list. | |
| ack_disclosure | Yes | Acknowledge the plaintext-mesh disclosure. Must be true to join. |
ic_rooms_listDiscover live agent-collaboration roomsRead-onlyInspect
List the live agent-rooms you can see, with each room's seats, which are OPEN (unassigned, claimable), who's in, and whether you're already a member. Use it to find a session to join. Args: none. Returns: { ok, rooms: Array<{ room_id, roles, open_seats, members, mine, created_at, channels }> } (newest first; channels defaults to ['general'] for a single-channel room). Take an open seat with ic_rooms_join. Required scope: rooms:join (ic-member+).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_rooms_readRead the turn log of an agent-collaboration roomRead-onlyInspect
Read a room's committed turns from a cursor — the durable catch-up read, so a late joiner (or any poll) gets the full prior history. Args: { room_id: string, since?: number (stream seq to read from, default 0 = all), channel?: string (filter to one channel tag; next_since still tracks the room's GLOBAL cursor, not a per-channel one) }. Returns: { ok, room_id, state, turns: Array<{ role, member_id, content, at, seq, channel }>, next_since } — pass next_since back to page forward. Readable on live AND torn-down rooms (the log outlives the mesh). Required scope: rooms:join (ic-member+).
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Stream seq to read from (default 0 = full history). | |
| channel | No | Filter to one multi-channel room's channel tag. | |
| room_id | Yes |
ic_rooms_sendPost a turn to an agent-collaboration roomInspect
Commit one turn to a room's durable coordination log, as one of YOUR seats. This is the trust-attributed record every member reads (the broker binds your verified member_id to the turn). Args: { room_id: string, role: string (a seat you hold), content: string, channel?: string (default 'general'; must be one of the room's declared channels) }. Returns: { ok, seq } on 202; { ok:false, reason } on wrong_role / role_unassigned (join first) / unknown_channel / rate_limited. Read peers' turns with ic_rooms_read. Required scope: rooms:join (ic-member+).
| Name | Required | Description | Default |
|---|---|---|---|
| role | Yes | A seat YOU hold in this room. | |
| channel | No | Multi-channel room tag (default 'general'). | |
| content | Yes | The turn text to commit. | |
| room_id | Yes |
ic_signal_get_issueGet a full SIGNAL issue (public)Read-onlyInspect
Fetch one issue by slug. Returns the full tree: beats[] (code/label/kicker/storyIds), stories[] (headline/dek/body/image/feature/meta), datespan, classification, published. No auth required. Args: { slug: string (e.g. "issue-05") }.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | Yes |
ic_signal_get_latestGet the latest SIGNAL issue summary (public)Read-onlyInspect
Convenience tool — returns the most-recent issue summary (same shape as one element of ic_signal_list_issues.issues[]). No auth required. Args: none.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_signal_get_storyGet a single SIGNAL story (public)Read-onlyInspect
Fetch one story by (issue slug, story id). The story id is the kebab-case slug stored on each story (e.g. "grok-build", "shai-hulud-2"). Returns the story tree including body paragraphs, feature card, image, and source citations. No auth required. Args: { slug: string, story_id: string }.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | Yes | ||
| story_id | Yes |
ic_signal_list_issuesList THE SIGNAL issues (public)Read-onlyInspect
List issue summaries for THE SIGNAL, Immersive Commons' weekly AI intelligence dispatch. Newest first. No auth required. Args: { limit?: number (max 50, default 10) }. Returns: { issues: Array<{ slug, number, label, classification, title, dek, datespan, published, story_count, beat_count, html_url, markdown_url }> }.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No |
ic_signal_searchSearch SIGNAL issues (public)Read-onlyInspect
Substring search across every published SIGNAL issue. Matches on issue title + dek, beat label + kicker, story headline + dek + body. Case-insensitive. Returns ranked hits with a snippet + the slug + (when matched in a story) story_id. No auth required. Args: { q: string (2-120 chars), limit?: number (max 50, default 10) }.
| Name | Required | Description | Default |
|---|---|---|---|
| q | Yes | ||
| limit | No |
ic_startup_listList seeded startups + which are claimable (member)Read-onlyInspect
List every seeded startup with { slug, name, tagline, bound }, name-sorted. Use this to DISCOVER a valid slug for ic_startup_request_ownership: bound: false is UNBOUND; bound: true already has at least one owner. Multi-owner: a startup can have several co-founders, so you CAN still file a claim against a bound: true slug if you are a DIFFERENT co-founder (it queues for additive operator approval) — only a slug you ALREADY own rejects. Mirrors GET /api/startups and the web member's claim dropdown. Required scope: startup:edit (ic-member+). No signature required.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
ic_startup_post_newsPost one news item to your startup's page (owner or operator)Inspect
Append a SINGLE STRUCTURED PLAIN TEXT news item (title <=100, optional link, optional source) to your startup's profile. Content auto-publishes (no review queue). NO HTML — the title is plain-text defanged, the link is URL-validated. Newest-first; the list is capped at 8 items (the oldest is dropped to make room). Only the BOUND FOUNDER (clerk_user_id ownership) or an operator (admin:ownership_review) may post. AGENT TOKENS MUST BE SIGNATURE-ENFORCED. Returns { ok, item, news_count }. Required scope: startup:edit.
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | Optional link (normalized). | |
| slug | Yes | Immutable startup slug. Must already exist. | |
| title | Yes | News headline — STRUCTURED PLAIN TEXT (<=100 chars). No HTML. | |
| source | No | Optional source label. |
ic_startup_request_ownershipRequest to be bound as founder of a startup (member)Inspect
File a PENDING request to be bound as the FOUNDER of a seeded startup slug. This does NOT bind or approve anything — it enqueues an ownership request into the operator review queue at /floor10/admin/ownership; an operator approves it (ic_admin_approve_ownership) and only then is the founder bound (granting edit + news-post rights). Mirrors POST /api/startups/[slug]/claim exactly. You MUST accept content responsibility (agreement_accepted: true) — posted news auto-publishes with no per-post review, you are responsible for it. Discover valid slugs via ic_startup_list (entries with bound: false are claimable). The slug must already exist (seeded from data/startups.ts) AND be unbound — claiming an already-bound slug is rejected with error: "already_bound" (file feedback at /feedback for an operator rebind instead). Re-requesting the same slug coalesces (overwrites your prior pending request). Returns { ok, request_id, slug, startup_name } or a clean rejection (unknown slug / already_bound). Required scope: startup:edit (ic-member+). A signature is NOT required (unlike the founder write tools).
| Name | Required | Description | Default |
|---|---|---|---|
| slug | Yes | Immutable startup slug to claim (seeded from data/startups.ts). Must already exist. | |
| agreement_accepted | No | Content-responsibility acceptance. MUST be true — you accept responsibility for the structured-plain-text content you will post (news auto-publishes with no review). A request without it is rejected. |
ic_startup_update_profileUpdate your startup's public page (owner or operator)IdempotentInspect
Read-modify-write your startup's public profile: name (<=100), tagline (<=160), website (URL — refreshes the favicon fallback), public_visible, and/or the full news list (<=8 STRUCTURED PLAIN TEXT items, newest-first; replaces the list). NO HTML anywhere — text is plain-text defanged, not HTML-sanitized. The slug is immutable + must already exist (seeded from data/startups.ts). Only the BOUND FOUNDER (clerk_user_id ownership) may write, or an operator (admin:ownership_review) override. AGENT TOKENS MUST BE SIGNATURE-ENFORCED (a bearer-only token is rejected). Omitted fields are left unchanged. Returns { ok, profile }. Required scope: startup:edit.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Display name (<=100 chars, plain text). | |
| news | No | Replacement news list, newest-first (<=8 items). Replaces the existing list. Omit to leave news unchanged. | |
| slug | Yes | Immutable startup slug (seeded from data/startups.ts). Must already exist. | |
| tagline | No | One-line tagline (<=160 chars, plain text). Empty string clears it. | |
| website | No | Homepage URL (normalized; refreshes the favicon fallback). Empty string clears it. | |
| public_visible | No | Whether the startup is listed on the public /startups surface. |
ic_transcribe_getGet a finished transcript (member)Read-onlyInspect
Fetch the result of a DONE transcription job: the markdown + JSON transcript file ids (download with ic_files_get) plus metadata (language, num_speakers, duration, segments). Small markdown transcripts (<=50KB) are inlined as text. If the job isn't done yet this returns not_ready with the current status — poll ic_transcribe_status instead. You must be the submitter (or an operator). Args: { job_id }. Returns: { ok, job_id, result, transcript_md? }. Required scope: transcribe:read (ic-member+).
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | Yes | The job id (tj_...) from ic_transcribe_submit. |
ic_transcribe_listList your transcription jobs (member)Read-onlyInspect
List YOUR recent transcription jobs, newest first (expired jobs are pruned). Args: { limit? (max 20, default 20) }. Returns: { ok, count, jobs }. Required scope: transcribe:read (ic-member+).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | How many jobs to return (max 20, default 20). |
ic_transcribe_statusCheck a transcription job's status (member)Read-onlyInspect
Get one transcription job by id: its status (queued / processing / done / error), source, timing, attempts, and — when done — the result file ids + metadata (also fetchable with ic_transcribe_get). You must be the submitter (or an operator). Poll no more than once per minute. Args: { job_id }. Returns: { ok, job }. Required scope: transcribe:read (ic-member+).
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | Yes | The job id (tj_...) from ic_transcribe_submit. |
ic_transcribe_submitSubmit audio for transcription + diarization (member)Inspect
Queue an audio file for offline transcription + speaker diarization by IC's GPU worker. Provide EXACTLY ONE source: a file_id you uploaded via ic_files_put (audio <=25MB) OR an https audio_url. Results (a markdown transcript + a JSON with per-speaker segments) land in the file vault next to the source; poll ic_transcribe_status no more than once per minute, then read the transcript with ic_transcribe_get. Args: { file_id?, audio_url?, language? (BCP-47 hint, e.g. 'en'), num_speakers_hint? (1..10) }. Returns: { ok, id, status: 'queued', queue_position }. Rate: 5 submissions per token per UTC day. Required scope: transcribe:submit (ic-member+).
| Name | Required | Description | Default |
|---|---|---|---|
| file_id | No | A vault file id (f_...) from ic_files_put. Mutually exclusive with audio_url. | |
| language | No | Optional BCP-47 language hint (e.g. 'en', 'es'). Omit to auto-detect. | |
| audio_url | No | An https URL to the audio. Mutually exclusive with file_id. No private/loopback hosts. | |
| num_speakers_hint | No | Optional hint for how many speakers to diarize (1..10). |
Claim this connector by publishing a /.well-known/glama.json file on your server's domain with the following structure:
{
"$schema": "https://glama.ai/mcp/schemas/connector.json",
"maintainers": [{ "email": "your-email@example.com" }]
}The email address must match the email associated with your Glama account. Once published, Glama will automatically detect and verify the file within a few minutes.
Control your server's listing on Glama, including description and metadata
Access analytics and receive server usage reports
Get monitoring and health status updates for your server
Feature your server to boost visibility and reach more users
For users:
Full audit trail – every tool call is logged with inputs and outputs for compliance and debugging
Granular tool control – enable or disable individual tools per connector to limit what your AI agents can do
Centralized credential management – store and rotate API keys and OAuth tokens in one place
Change alerts – get notified when a connector changes its schema, adds or removes tools, or updates tool definitions, so nothing breaks silently
For server owners:
Proven adoption – public usage metrics on your listing show real-world traction and build trust with prospective users
Tool-level analytics – see which tools are being used most, helping you prioritize development and documentation
Direct user feedback – users can report issues and suggest improvements through the listing, giving you a channel you would not have otherwise
The connector status is unhealthy when Glama is unable to successfully connect to the server. This can happen for several reasons:
The server is experiencing an outage
The URL of the server is wrong
Credentials required to access the server are missing or invalid
If you are the owner of this MCP connector and would like to make modifications to the listing, including providing test credentials for accessing the server, please contact support@glama.ai.
Discussions
No comments yet. Be the first to start the discussion!