Human Agent Cowork MCP Server
MCP server to implement Human Agent CoWork protocol
Ask AI about Human Agent Cowork MCP Server
Powered by Claude Β· Grounded in docs
I know everything about Human Agent Cowork MCP Server. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
@cowork/mcp-server
Human-Agent Collaboration Primitives as an MCP Server
Add trust, handoffs, and accountability to any AI agent. Production-ready implementation of the COWORK Protocol.
Status
v0.1.1 β Weeks 1, 2 & 3 Complete β | Ready for npm Publish
| Component | Status | Verified |
|---|---|---|
| 14 MCP tools | β All registered | cowork_check_handoff added (14th tool) |
| Authentication | β Open + closed mode | sales-agent token validated, closed mode enforced |
| Trust scoring | β Per (agent, domain) | 0.3 initial, escalate/suggest/act working, auto-promote at 0.8 |
| Mode determination | β Two-factor logic | High-risk field + trust level, policy-aware |
| Policy engine | β Constraints + attribution | 5 constraint types, policy_id in response, wildcard matching |
| Agent-to-policy mapping | β Three-way join | Explicit mappings: (agent, domain, policy_id) |
| Bulk operations | β Approve/reject N | cowork_bulk_approve, cowork_bulk_reject fully functional |
| Audit trail | β SHA-256 hash chain | Sentry proxy, proposal β execution trace linking |
| Volume cap enforcement | β Per (agent, domain) | 50 proposals/hour, checked at propose time, volume_remaining in response |
| Trust decay | β Lazy evaluation | 1% per day decay applied on-read, configurable decay_per_day |
| Handoff callbacks | β Full round-trip | Agent escalates β human resolves β agent polls cowork_check_handoff β continues |
| Automated test suite | β 49 tests passing | Jest: 10 trust, 17 policy, 10 auth, 12 integration tests |
| Policy attribution | β Per-proposal | Response includes policy_id, policy_description, rules_checked, mapping_found |
| npm publish | β Ready | All 95% of protocol implemented (36/38 primitives) |
Install from source: npm install && npm run build && npm run start
npm registry: Coming within 1 week after quality testing
What This Does
14 MCP Tools that add collaboration primitives to any AI agent:
| Tool | Primitive | What it does |
|---|---|---|
cowork_propose | Intent Declaration | Agent proposes before acting. Trust score + field type determine: act / suggest / escalate |
cowork_approve | Approval Signal | Human approves proposal. Trust +0.02, closes positive feedback loop |
cowork_override | Override Signal | Human corrects agent. Trust degrades. 5 categories Γ 4 severity levels |
cowork_check_trust | Trust Score | Trust level + accuracy + operating mode for any (agent, domain) |
cowork_handoff | Context Packet | Escalate to human with structured context: reason, confidence, attempted actions |
cowork_check_handoff | Handoff Callback | Agent polls for resolved handoffs with instructions. Enables agent continuation after human escalation |
cowork_log | Action Attribution | Log action with actor (agent / human / collaborative) |
cowork_validate_policy | Action Scope | Pre-flight policy check. Field constraints + policy attribution. Hard-stop vs warning |
cowork_bulk_approve | Batch Approval | Approve 50+ proposals in one human decision |
cowork_bulk_reject | Batch Override | Reject multiple proposals with a single reason |
cowork_resolve_handoff | Handoff Resolution | Human resolves escalation. Optionally hands work back with instructions |
cowork_audit_trail | Action Attribution | Full chain: propose β approve β execute β verify |
cowork_governance_report | Intervention Map | Detect orphaned executions, slow decisions, missing approvals |
cowork_status | Dashboard | Trust scores, override rates, pending proposals, timeline |
Installation
Option 1: Local Development (Works Now) β
git clone https://github.com/kamesh231/human-agent-cowork-mcp-server.git
cd human-agent-cowork-mcp-server
npm install
npm run build
npm run start
Expected output:
π€ COWORK MCP Server v0.1.0 started
Auth: open mode (demo) | Mode: suggest | Trust default: 0.3
Claude Desktop
Edit ~/.config/Claude/claude_desktop_config.json:
{
"mcpServers": {
"cowork": {
"command": "node",
"args": ["/full/path/to/human-agent-cowork-mcp-server/build/index.js"]
}
}
}
Restart Claude Desktop β cowork tools appear.
Claude Code
claude mcp add cowork node "$(pwd)/build/index.js"
Option 2: Global npm (Coming After Week 3) β³
# Not yet available. Will work after npm publish:
npm install -g @cowork/mcp-server
How to Implement
Step 1 β Demo Mode (No Auth)
By default the server runs in open mode β any agent_id is accepted, no token needed.
npm run start
# Auth: open mode (demo) | Mode: suggest | Trust default: 0.3
All 13 tools immediately available. Good for prototyping.
Step 2 β Register Your Agents (Closed Auth)
Generate tokens and add them to cowork.config.yaml:
# Generate token + hash for each agent
node -e "
const {generateToken, hashToken} = require('./build/auth.js');
const t = generateToken();
console.log('token:', t);
console.log('hash:', hashToken(t));
"
# cowork.config.yaml
agents:
- id: "sales-agent"
token: "sk-cowork-abc123..." # Dev: plaintext in config
- id: "support-agent"
token: "sk-cowork-xyz789..."
Server output changes to: Auth: closed mode (2 agents)
Production mode: Use
token_hashinstead oftokenand load plaintext tokens via.env
Step 3 β Map Each Agent to Its Policies
β³ Week 3 feature β available soon. Currently all agents share the global policy.
The problem it solves: With one global policy and multiple agents, you cannot answer "which
policy fired for which agent?" You can't verify that sales-agent is constrained by CRM rules
while support-agent gets support rules β or test that both share a policy in the same domain.
Three-section design (policies defined once, referenced by ID in mappings):
# Section 1 β Named rule sets. Define once, share across many agents.
policies:
- id: "crm-write-policy"
description: "Standard write access for CRM fields"
rules:
- field: "deal_stage"
constraint: "high_risk" # always requires human review
- field: "amount"
constraint: "value_range"
min: 0
max: 500000
- field: "commission"
constraint: "readonly"
reason: "Finance team only"
- id: "support-write-policy"
description: "Write access for support ticket fields"
rules:
- field: "priority"
constraint: "enum"
values: ["low", "medium", "high", "critical"]
- field: "billing_*"
constraint: "readonly"
reason: "Billing fields require finance approval"
# Section 2 β Agent identity only. No rules embedded here.
agents:
- id: "sales-agent"
token: "sk-cowork-..."
- id: "support-agent"
token: "sk-cowork-..."
# Section 3 β Explicit three-way join: who Γ where Γ which rules
mappings:
- agent_id: "sales-agent"
domain: "crm.deals"
policy_id: "crm-write-policy"
- agent_id: "support-agent"
domain: "support.tickets"
policy_id: "support-write-policy"
# 2 agents β 1 policy: support-agent uses same CRM rules as sales-agent
- agent_id: "support-agent"
domain: "crm.deals"
policy_id: "crm-write-policy"
# 1 agent β 2 policies: sales-agent has support rules when working tickets
- agent_id: "sales-agent"
domain: "support.tickets"
policy_id: "support-write-policy"
Blocking behavior: If an agent proposes in a domain with no mappings entry, the proposal
is blocked and escalated to a human asking for permission. No silent fallback.
Proposal response will include which policy fired:
{
"proposal_id": "uuid",
"mode": "suggest",
"trust_level": 0.3,
"high_risk_field": true,
"policy_id": "crm-write-policy",
"policy_description": "Standard write access for CRM fields",
"policy_rules_checked": 3,
"mapping_found": true
}
This makes policy attribution testable: assert(response.policy_id === "crm-write-policy")
is unambiguous regardless of which agent made the proposal.
Why not RBAC? The structure looks similar (user β role β permission) but the semantics
differ: policies here are dynamic β the same policy produces escalate, suggest, or act
based on the agent's earned trust score. RBAC is binary (allowed/denied). COWORK is gradient
(how much autonomy, right now, given this agent's track record). See WEEK3_PLAN.md
for the full design rationale.
Step 4 β Configure Trust & Authority (Global Defaults)
# cowork.config.yaml
trust:
default_level: 0.3 # All agents start supervised
auto_promote_after: 20 # Promote after 20 approvals
auto_promote_threshold: 0.8 # At 80%+ approval rate
auto_demote_after: 3 # 3 consecutive overrides β demotion
decay_per_day: 0.01 # Trust decays 1%/day without activity (β³ Week 3)
authority:
default_mode: "suggest"
volume_cap: 50 # Max proposals/hour per agent (β³ enforced in Week 3)
high_risk_fields: # Global: always require human review
- "deal_stage"
- "owner"
- "commission"
- "utm_*"
- "billing_*"
- "password"
- "permissions"
Step 5 β Wire Into Your Agent
// Agent proposes before acting
const proposal = await cowork_propose({
agent_id: "sales-agent",
agent_token: "sk-cowork-...",
domain: "crm.deals",
action: "update_deal",
target: "deal_12345",
proposed_change: JSON.stringify({ deal_stage: "closed_won" }),
confidence: 0.92,
reasoning: "All criteria met: budget approved, stakeholder consensus",
field: "deal_stage"
});
// Handle the three operating modes
if (proposal.mode === "act") {
// Trust β₯ 0.8, proceed autonomously
await db.update("deals", "deal_12345", { deal_stage: "closed_won" });
} else if (proposal.mode === "suggest") {
// Trust 0.5β0.8, or field is high-risk β wait for human review
// deal_stage is in high_risk_fields, so always lands here
notify.send(`π Awaiting review: ${proposal.proposal_id}`);
} else {
// Trust < 0.5, escalate to human
await cowork_handoff({
agent_id: "sales-agent",
agent_token: "sk-cowork-...",
domain: "crm.deals",
reason: "Trust too low to proceed",
confidence: proposal.confidence,
attempted_actions: JSON.stringify(["cowork_propose returned escalate"]),
context: JSON.stringify({ proposal_id: proposal.proposal_id }),
handoff_mode: "escalate"
});
}
Step 6 β Integrate Human Feedback
// Approve β closes the positive feedback loop
await cowork_approve({
proposal_id: "uuid",
agent_id: "sales-agent",
domain: "crm.deals",
feedback: "Looks good β legal confirmed"
});
// Effect: trust +0.02, proposal marked approved
// Correct β closes the negative feedback loop
await cowork_override({
agent_id: "sales-agent",
domain: "crm.deals",
action_description: "Deal closure was premature",
override_type: "agent_wrong",
severity: "high",
description: "Contract still being negotiated"
});
// Effect: trust -0.12 (0.08 Γ 1.5 severity), consecutive_overrides +1
How Mode Is Determined
cowork_propose uses two-factor logic to set the operating mode:
Factor 1: High-Risk Field Check
If the field being modified is in high_risk_fields (or per-agent policy rules after Week 3):
deal_stage, owner, commission, utm_*, billing_*, password, permissions
β Mode = "suggest" regardless of trust level
Factor 2: Trust-Based Check (for non-high-risk fields)
trust < 0.5 β mode = "escalate" (human must handle it)
0.5 β€ trust < 0.8 β mode = "suggest" (propose and wait for approval)
trust β₯ 0.8 β mode = "act" (proceed autonomously)
Verified Response Structure
Tested and confirmed from live test run:
{
"proposal_id": "9f8710ef-c245-4c19-9ff1-810ac300c185",
"action_id": "e5c3a1d2-4f6b-11ec-81d3-0242ac130003",
"mode": "escalate",
"trust_level": 0.3,
"confidence": 0.85,
"high_risk_field": false,
"policy_warnings": 0,
"message": "π¨ ESCALATED: Trust (0.30) too low. Proposal 9f8710ef..."
}
Key field names: trust_level (not trust.score), high_risk_field (boolean).
Domain & Agent Mapping
Agents Are Explicitly Registered
agents:
- id: "sales-agent"
token: "sk-cowork-abc..."
- id: "support-agent"
token: "sk-cowork-xyz..."
Every tool call must include matching agent_id + agent_token. Server rejects unknown agents in closed mode.
Domains Are Agent-Chosen (Organic)
Domains are not pre-registered β agents name them at proposal time. Any string works:
// Domains are just strings agents choose
domain: "crm.deals" // sales agent's scope
domain: "support.tickets" // support agent's scope
domain: "docs.api-ref" // documentation agent's scope
Trust is tracked per (agent_id, domain) pair:
sales-agent : crm.deals β trust 0.85 β mode: act
sales-agent : crm.contacts β trust 0.40 β mode: suggest
sales-agent : support.tickets β trust 0.30 β mode: escalate
support-agent : support.tickets β trust 0.72 β mode: suggest
Same agent can be trusted in one domain but not another.
Override Categories & Severity
When a human corrects an agent, they categorize why:
| Category | Base Impact | When to Use |
|---|---|---|
agent_wrong | β0.08 | Factual or logical error |
missing_context | β0.03 | Should have escalated, didn't have info |
edge_case | β0.02 | Unusual situation, hard to anticipate |
human_preference | β0.01 | Agent was correct, human prefers different approach |
policy_change | 0.00 | Rules changed β not the agent's fault |
Severity multiplier scales the base impact:
| Severity | Multiplier | Example |
|---|---|---|
low | 0.5Γ | Minor wording preference |
medium | 1.0Γ | Standard correction |
high | 1.5Γ | Serious error with real consequences |
critical | 2.5Γ | Breach of policy or major failure |
Example: agent_wrong + high severity = β0.08 Γ 1.5 = β0.12 trust
Volume Cap Enforcement
Agents are rate-limited to prevent runaway behavior. The limit is per (agent, domain) pair:
# cowork.config.yaml
authority:
volume_cap: 50 # Max proposals per hour
Enforcement: Every cowork_propose call checks the proposal count in the last 60 minutes for that (agent_id, domain). If the agent would exceed the cap with this proposal, the proposal is rejected with VolumeCapError.
Response includes feedback:
{
"volume_cap": 50,
"volume_remaining": 12,
"proposal_id": "uuid",
"mode": "suggest"
}
This allows agents to monitor their own rate and back off voluntarily.
Trust Decay
Agents lose trust gradually when inactive. This prevents "earn trust once, coast forever."
# cowork.config.yaml
trust:
decay_per_day: 0.01 # 1% per day
How it works:
- Decay is applied lazily on-read (no background job needed)
- Each time
cowork_check_trustorcowork_proposeruns, the trust score is recalculated - Formula:
new_score = current_score - (days_since_last_activity Γ decay_per_day) - Minimum trust: 0.1 (never decays below this)
Example: If an agent at 0.8 trust stops proposing for 10 days:
0.8 - (10 Γ 0.01) = 0.8 - 0.1 = 0.7 (now in "suggest" mode instead of "act")
Reset decay by proposing again, or be approved. Each approval and proposal activity timestamp resets the decay clock.
Handoff Callback Loop
When agents escalate via cowork_handoff, they don't just disappear. Humans can hand the work back with instructions, and the agent polls for those instructions.
Agent Flow
// Step 1: Agent escalates
const handoff = await cowork_handoff({
agent_id: "sales-agent",
domain: "crm.deals",
reason: "Trust too low to modify deal_stage",
confidence: 0.85,
attempted_actions: JSON.stringify(["check budget", "verify stakeholders"]),
context: JSON.stringify({ deal_id: "12345", issue: "..." })
});
// Agent receives handoff_id and waits
const handoff_id = handoff.handoff_id;
// Step 2: Human resolves with instructions (happens in UI or via cowork_resolve_handoff)
// Human chooses: approve and/or hand back with instructions
// Example: "You can proceed, but only if both stakeholders have confirmed in writing"
// Step 3: Agent polls for the resolution and instructions
const callback = await cowork_check_handoff({
agent_id: "sales-agent",
domain: "crm.deals" // optional β omit to check all domains
});
if (callback.pending_handoffs.length > 0) {
const handoff = callback.pending_handoffs[0];
if (handoff.hand_back === true) {
// Human handed work back with instructions
console.log("Instructions:", handoff.instructions);
// "Check for written stakeholder confirmation before proceeding"
// Verify constraint and try again
if (stakeholders_confirmed) {
await cowork_propose({ /* same proposal */ });
}
}
}
Human Flow
// Human sees escalated work in dashboard
const status = await cowork_status({ agent_id: "sales-agent" });
// Shows pending handoffs with agent's reasoning and context
// Human resolves with instructions
await cowork_resolve_handoff({
handoff_id: "uuid",
resolution: "approved",
hand_back: true, // Agent can continue
instructions: "Proceed only if both stakeholders have written confirmation in the deal notes"
});
// Agent's next cowork_check_handoff call returns this instruction
// Agent can now take informed action or ask clarifying questions
Real-World Cases This Protocol Addresses
CRM Data Integrity (HubSpot Case)
The CRM case study describes an agent with full write access that silently corrupted data for 3 weeks. Root cause: no field restrictions, no volume caps, no approval flow.
What COWORK provides:
high_risk_fieldsblocks direct writes to deal_stage, commission, utm_*volume_cappauses agent at 50 proposals/hour (enforced in Week 3)cowork_proposecreates a staging layer before any writecowork_overridewith categorized reason creates a feedback loop
Support Handoff Failures (Intercom Case)
50% of conversations required human handoff. Context was lost at every handoff β humans re-read full transcripts and customers repeated themselves.
What COWORK provides:
cowork_handoffcarries structured context: reason, confidence, attempted_actions- Per-domain trust (
support.ticketsseparate frombilling.issues) cowork_resolve_handofflets human hand work back with instructions (callback in Week 3)
Cross-Environment Context Loss
Two agents (Claude Desktop + Claude Code) sharing a filesystem but not sharing decision state. The em-dash incident: Claude Desktop approved 80 replacements without knowing why they were made.
What COWORK provides:
cowork_handoffcontext packet carries decision state, not just output statecowork_logwithactor: "agent"attributes which environment made the change- Timeline events allow reconstruction of cross-environment sequence
Testing
Automated Test Suite (Jest) β
npm test
49 tests, 4 categories, all passing:
Trust & Mode Determination (10 tests)
- Initial trust defaults to 0.3 β mode=escalate
- High-risk field (deal_stage) β mode=suggest regardless of trust
- Trust 0.85 β mode=act (autonomous)
- Approval increases trust +0.02
- Override with severity multiplier (high: 1.5Γ) decreases trust correctly
- 3 consecutive overrides triggers demotion
- Trust decay applied correctly (1% per day)
- Auto-promotion at 80% approval rate after 20 approvals
Policy Mapping & Attribution (17 tests)
- 2 agents + 1 policy: sales-agent & support-agent both use crm-write-policy
- 1 agent + 2 policies: sales-agent uses crm-write-policy in crm.deals AND support-write-policy in support.tickets
- Unmapped domain returns mapping_found=false (escalates gracefully)
- Policy constraints evaluated: high_risk, readonly, value_range, enum, regex
- Wildcard matching works (billing_* matches billing_amount, billing_status)
- Policy attribution in response: policy_id, policy_description, rules_checked
Authentication (10 tests)
- sales-agent token validates against config
- Invalid token throws AuthError
- Open mode accepts any agent_id
- Closed mode rejects unknown agents
- Token generation and hashing work correctly
Integration (12 tests)
- Full cowork_propose flow with auth + policy resolution
- Volume cap enforcement (50/hour) with volume_remaining feedback
- High-risk field detection + policy rules checked count
- Handoff callback loop: escalate β resolve β agent polls β continues
- Mode determination respects both high-risk check AND trust-based check
Coverage
npm test -- --coverage
Generates coverage report for all 14 tools. Current coverage: 92% of core paths.
MCP Inspector (Interactive)
npm run inspect
Opens browser-based tool to call any of the 14 tools manually, see live responses, inspect database state.
Architecture
| File | Purpose |
|---|---|
src/index.ts | 14 MCP tool handlers, auth middleware, proposal β response pipeline |
src/trust.ts | Atomic trust mutations via SQLite transactions, decay calculation |
src/storage.ts | SQLite schema: 7 tables (proposals, trust_scores, actions, overrides, handoffs, timeline, audit_log), all queries, migration support |
src/auth.ts | Token generation, verification, open/closed mode switching |
src/policy.ts | Policy engine: 3-way mapping resolution, 5 constraint types, wildcard matching, high-risk field detection |
src/config.ts | Config schema: policies (named rule sets), agents (identity), mappings (explicit joins), trust defaults, authority rules |
src/audit.ts | Audit chain, governance issue detection, proposalβexecution linking |
src/bulk-decision.ts | Batch approve/reject operations with atomic updates |
src/notify.ts | Multi-channel notifications framework (placeholder for email/Slack/webhook) |
src/sentry/ | Audit proxy β intercepts tool calls, intent validation, hash-chain logging |
tests/unit/ | 37 unit tests: trust (10), policy (17), auth (10) |
tests/integration/ | 12 integration tests: full MCP flows with auth + policy resolution |
Production characteristics:
- β
All trust mutations in
BEGIN EXCLUSIVESQLite transactions (no TOCTOU races) - β Full TypeScript with Zod input validation on all 14 tools
- β Explicit policy mapping (3-way join) with attribution in response
- β Open mode for prototyping, closed mode for production
- β SHA-256 hash chain in Sentry traces (tamper-evident)
- β Volume cap enforcement at propose time with feedback
- β Trust decay applied lazily on-read (no background job)
Protocol Alignment
| Category | Primitives | Implemented | Status |
|---|---|---|---|
| Trust | Score, Threshold, Evidence, Decay, Auto-Promote | 5/5 | β Complete |
| Authority | Action Scope, Volume Cap, High-Risk Fields | 3/3 | β Complete |
| Handoff | Context Packet, Escalation Trigger, Callbacks | 3/3 | β Complete (Week 3) |
| Feedback | Override Signal, Approval Signal, Bulk | 3/3 | β Complete |
| Communication | Confidence, Reasoning, Intent Declaration | 3/3 | β Complete |
| Observability | Attribution, Timeline, Governance | 3/3 | β Complete |
| Policy | Validation, Attribution, Constraint Evaluation | 3/3 | β Complete (Week 3) |
| Deferred to v0.2.0 | Quality Metrics, Structured Reasoning Schema | 2/2 | β³ Future |
| Total | 36 core + 2 advanced | 36/38 (95%) | β Week 3 Complete |
Full detail: PROTOCOL_ALIGNMENT.md
Week 3 Implementation β
| Day | Feature | Status | Impact |
|---|---|---|---|
| 1 | Agent-to-policy mapping (3-way join) | β Complete | Policies now explicitly named, reusable, attributable in response |
| 2β3 | Automated test suite (Jest, 49 tests) | β Complete | Full coverage: trust, policy, auth, integration flows |
| 4 | Volume cap enforcement (50/hour) + trust decay (1%/day) | β Complete | Both checked at runtime, lazy evaluation for decay |
| 5 | Handoff callbacks (cowork_check_handoff) | β Complete | Agent can poll for human instructions, enables continuation after escalation |
Detailed plan & implementation notes: WEEK3_PLAN.md
What's ready:
- β 14 tools fully functional
- β 36/38 COWORK protocol primitives implemented (95%)
- β Production-ready: SQLite transactions, atomic trust mutations, Zod validation
- β 49 automated tests all passing
- β Policy attribution testable (policy_id in response)
- β Volume cap feedback in response (volume_remaining field)
- β Handoff callback loop fully operational
What's deferred to v0.2.0:
- Quality metrics collection (primitive #37)
- Structured reasoning schema (primitive #38)
Storage
- Default: SQLite at
./cowork.db - Tables: proposals, trust_scores, actions, overrides, handoffs, timeline, audit_log
- Access:
sqlite3 cowork.dbor usecowork_statusandcowork_audit_trailtools - Sentry traces: Separate DB at
./cowork-traces.dbwith hash chain
Links
- COWORK Protocol Spec: https://github.com/kamesh231/cowork-protocol
- This Repo: https://github.com/kamesh231/human-agent-cowork-mcp-server
- Week 3 Plan: WEEK3_PLAN.md
- Protocol Alignment: PROTOCOL_ALIGNMENT.md
License
MIT β Use freely in commercial or open-source projects.
