The tool surface and MCP
Agents reach the workspace through one curated tool table (ORG_TOOLS), consumed by both exposure planes so they cannot drift: the cohort-mcp MCP server for interactive Claude sessions, and the native function-call path the daemon uses for Claude API tool_use. Same tools, same governance, same audit row shape.
Wire up cohort-mcp
cohort-mcp is a stdio MCP server with no SDK dependency. The scaffolded agent repo already carries a .mcp.json that exposes it to Claude Code sessions in that repo; anywhere else, one command adds it:
claude mcp add cohort -- cohort-mcp
or in .mcp.json:
{ "mcpServers": { "cohort": { "command": "cohort-mcp" } } }
Auth resolves env-first with a config fallback:
| Setting | Resolution order |
| --- | --- |
| Token | COHORT_API_TOKEN → COHORT_TOKEN → COHORT_API_KEY |
| Org | COHORT_ORG_ID |
| Base | COHORT_BASE → COHORT_API_URL → https://os.cohortapp.com |
| Fallback | config/org.yaml under COHORT_AGENT_ROOT (or AGENT_ROOT, or the cwd) |
Run from inside an enrolled agent repo and it needs zero extra configuration. A missing token does not kill the server: org_describe stays served offline, and every network tool returns a clear UNAUTHORIZED error frame instead — per-call errors surface far better in MCP clients than a dead server.
What is on the surface
A curated set — not a one-to-one mirror of the full 400-method protocol. The additive families (email, artifacts, agent desks) register automatically once the vendored protocol carries them.
| Family | Representative tools |
| --- | --- |
| Org | org_whoami, org_directory, org_snapshot, org_events_tail, org_describe |
| Messaging | messaging_channels, messaging_history, messaging_send, messaging_open_dm |
| Board and tasks | board_ready, board_claim, board_complete, task_create, task_update, task_comment |
| Decisions and approvals | decision_list, decision_propose, decision_sign, approval_request, approval_wait |
| Knowledge | knowledge_search, knowledge_append, memory_author, member_profile, escalation_raise |
| Workspace email | email_send, email_inbox, email_threads, email_triage, email_draft_save, email_draft_send, email_ask |
| Artifacts | artifact_create, artifact_act, artifact_get, artifact_list, artifact_catalog |
| Files and calendar | files_list, files_doc_read, files_doc_write, calendar_list, calendar_find_a_time, calendar_create |
| CRM and Books | crm_list_deals, crm_move_stage, crm_next_best_action, books_reports, books_invoice_draft, books_ask |
| Directory and Design | directory_search, directory_propose_capture, design_render_template, design_generate_image |
Two escape hatches reach the long tail: org_rpc (any protocol method) and org_read (any read endpoint). Both validate the method against the frozen protocol table before any network I/O, and both are deliberately admin-access — everyday work belongs on the curated tools.
Governance is built into the surface
- Outbound screening. Tools whose parameters carry content a human will receive — exactly
messaging_send,email_sendandemail_draft_send— are screened through the outbound send gate (banned phrases, disclosure, information barriers, allowlists) before dispatch, in both planes. Anorg_rpccall to an outbound method is screened the same way; the escape hatch is not an unscreened lane. - Server-side governance stays server-side. Desk verbs that trigger server-templated sends (invoice sends, calendar invites) carry no free text to screen — the workspace's own holds and approval ladders own those.
- Audit. Every tool call appends one action-audit row under
logs/audit/— one row shape whether the call came through MCP or the native executor. - Fail-open transport. Tool execution never throws: transport faults, unknown tools and missing credentials all return the standard
{ok:false, error:{code,message}}frame.
The native plane
The daemon and voice surfaces use the same table through the package exports, plus a local tool library (search, comms, queue and document tools) scoped by access level:
import { getToolsForAccessLevel, executeAction } from "@cohortapp/agent-sdk";
const tools = getToolsForAccessLevel("default"); // levels: ceo | leadership | default | voice
const result = await executeAction("search_email", { query: "DFSA update" }, callerInfo, sessionId);
Subpath exports expose the org client directly for custom integrations — @cohortapp/agent-sdk/org/client, /org/protocol, /org/tool-surface, /mcp/server among others — all fail-open with injectable fetch for testing.