# OTP (npm · otp-mcp-server)

Put AI agents on your org chart: seats, KPIs, to-dos, meetings and logged work, next to the people.

- Trust score: 62/100 (medium)
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-11-05

## Components

- remote · `orgtp.com`: 38/100, [markdown](https://verifymcp.io/servers/david-steel-otp/api-mcp.md), [page](https://verifymcp.io/servers/david-steel-otp/api-mcp)
- remote · `orgtp.com`: 75/100, [markdown](https://verifymcp.io/servers/david-steel-otp/api-mcp-public.md), [page](https://verifymcp.io/servers/david-steel-otp/api-mcp-public)
- npm · `otp-mcp-server`: 62/100 (this document), [markdown](https://verifymcp.io/servers/david-steel-otp/otp-mcp-server.md), [page](https://verifymcp.io/servers/david-steel-otp/otp-mcp-server)

## Channel facts

- Registry: `npm`
- Package: `otp-mcp-server`
- Version: `0.5.3`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-11-05.

- **Supply Chain Security**: 98/100
  - No malware found by supply-chain analysis.
  - No known CVEs affecting this package version or its production dependencies.
  - No install/post-install scripts declared.
  - 30 of 92 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 19/100
  - Repository check failed: no source repository is declared.
  - Provenance check failed: no build-provenance attestation is published.
  - Clear OSI-approved license (MIT).
  - Actively maintained (last published 5 days ago).
  - Security-disclosure policy not yet verified: we couldn't inspect the source repository.
- **Schema Quality & AI Usability**: 68/100
  - AI-judged instruction clarity (good).
  - Context-footprint check failed: tool/resource definitions use about 8900 tokens (~134/item across 66 items; 66 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 0/100
  - Stability not yet verified: not enough scan history yet (needs a 30-day window).
- **Tool Coverage**: 95/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 85% of tool parameters carry a description.
- **Tool Safety**: 75/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - 0 of 2 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation; "publish_oos" implies "publish" and declares no destructiveHint at all, which the MCP spec reads as destructive by default.
  - An AI judge read all 66 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

**Unverified: 1 category.** A category scored 0 because we could not verify it: a data source with nothing on this package, evidence we could not reach, or a check we could not run. We only credit what we can confirm.

## Install

### How do I install the OTP MCP server?

OTP runs locally as an npm package, launched with npx -y otp-mcp-server. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add david-steel-otp -- npx -y otp-mcp-server
```

### Cursor

```json
{
  "mcpServers": {
    "david-steel-otp": {
      "command": "npx",
      "args": [
        "-y",
        "otp-mcp-server"
      ]
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "david-steel-otp": {
      "command": "npx",
      "args": [
        "-y",
        "otp-mcp-server"
      ]
    }
  }
}
```

### Codex

```bash
codex mcp add david-steel-otp -- npx -y otp-mcp-server
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "david-steel-otp": {
      "type": "local",
      "command": [
        "npx",
        "-y",
        "otp-mcp-server"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add david-steel-otp --command npx --arg -y --arg otp-mcp-server
```

### Hermes

```yaml
mcp_servers:
  david-steel-otp:
    command: "npx"
    args: ["-y", "otp-mcp-server"]
```

### Netclaw

```json
{
  "McpServers": {
    "david-steel-otp": {
      "Transport": "stdio",
      "Command": "npx",
      "Arguments": [
        "-y",
        "otp-mcp-server"
      ]
    }
  }
}
```

### Vellum

```bash
assistant mcp add david-steel-otp -t stdio -c npx -a -y otp-mcp-server
```

### Other

```json
{
  "mcpServers": {
    "david-steel-otp": {
      "command": "npx",
      "args": [
        "-y",
        "otp-mcp-server"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-10-31 (score 62, +15)

- [security improvement] Malware scan: unverified → pass

### 2026-10-30 (score 47)

First indexed and scored.

## MCP tools (66)

### `register_agent` (~392 tokens)

Put YOURSELF on this organization's OTP org chart. Call this once, when a human gives you an OTP connection code and asks you to connect. Read your own system prompt / CLAUDE.md and describe yourself honestly: your name, your role, what you own, what you explicitly do not own, and up to 3 KPIs you should be measured on. OTP creates your seat, seeds your KPIs, and binds this connection to you, so from then on OTP knows which agent is calling. If the humans ALREADY drew your seat on the chart and gave you its id, call claim_seat with that id instead -- register_agent would create a duplicate. Safe to retry: if you are already registered it just tells you who you are. Do not invent a KPI you have no way to move.

Input parameters:

- `doesNotOwn` (string): What is explicitly NOT yours, so the chart has no overlap. E.g. 'Client comms, strategic decisions'
- `kpis` (array): Up to 3 KPIs you should be judged on. Omit rather than invent.
- `name` (string, required): What you are called. E.g. 'Forecaster', 'Dash'
- `owns` (string): What you are accountable for. E.g. 'Weekly revenue forecast, pipeline coverage, spend pacing'
- `reportsTo` (string): The chart seat you report to (e.g. 'HUM_NATEFOSS'). Use it ONLY if the human's connection code gave you one; otherwise leave it out and OTP reports you to whoever enrolled you.
- `role` (string): One line on what you do. E.g. 'Reads the numbers and calls the trend before it lands'
- `systemPrompt` (string): Your full system prompt / CLAUDE.md, verbatim, if you can read it. Stored as your brain so you survive being rebuilt elsewhere.

### `claim_seat` (~309 tokens)

Take a seat that is ALREADY drawn on this organization's org chart. Use claim_seat when the humans drew your seat before you connected -- they will give you its exact id (e.g. 'AGT_RADAR') in the connection code or by name; use register_agent only when you have NO seat on the chart yet (it creates a new one, and would create a duplicate here). Pass external_id exactly as given. Optionally add, honestly from your own system prompt / CLAUDE.md: your role, what you own, what you explicitly do not own, and up to 3 KPIs. OTP binds this connection to that seat, so from then on OTP knows which agent is calling. Safe to retry: if this connection already holds the seat it just says so.

Input parameters:

- `doesNotOwn` (string): What is explicitly NOT yours, so the chart has no overlap. E.g. 'Client comms, strategic decisions'
- `external_id` (string, required): The chart seat to claim, exactly as the human gave it. E.g. 'AGT_RADAR'
- `kpis` (array): Up to 3 KPIs you should be judged on. Omit rather than invent.
- `owns` (string): What you are accountable for. E.g. 'Weekly revenue forecast, pipeline coverage, spend pacing'
- `role` (string): One line on what you do. E.g. 'Reads the numbers and calls the trend before it lands'

### `get_my_seat` (~115 tokens)

Who YOU are on this organization's chart: your seat id, name, and role, who you escalate to, your immediate colleagues (peers under the same manager, names and types only), and the KPIs you are measured on. Resolved from this connection's bound identity, never from arguments, so it always answers about the agent calling. If it says this key is not bound to a seat, you are on an org-wide connection: call register_agent to take a seat, then this same connection is your identity.

### `log_work` (~208 tokens)

Report a piece of work you have COMPLETED, so it shows on your chart tile and in the organization's activity. One call per completed piece of work, after it is done -- never for work you only planned or started. summary says what you did, in one or two sentences. Requires this connection to hold a seat (register_agent first); if it refuses with SEAT_NOT_BOUND, register and try again. Do not log the same work twice, and do not invent cost_cents you cannot substantiate.

Input parameters:

- `category` (string): Optional bucket for the work, e.g. 'reporting', 'outreach', 'triage'
- `cost_cents` (integer): What the work cost in cents (tokens/API spend), if you know it. Omit for 0; never estimate upward.
- `summary` (string, required): What you did, past tense, <= 500 chars. E.g. 'Triaged 14 inbound emails, drafted 3 replies for approval'

### `browse_oos` (~144 tokens)

Browse published Organizational Operating Systems on OTP. Filter by industry, org size, template type, or quality tier. Returns a list of published OOS files with org metadata.

Input parameters:

- `industry` (string): Filter by industry (e.g. 'digital_marketing', 'saas', 'healthcare')
- `limit` (number): Results per page (default 20, max 100)
- `page` (number): Page number (default 1)
- `size` (string): Filter by organization size
- `sort` (string): Sort order: newest (default), claims count, or quality tier
- `template` (string): Filter by OOS template type

### `search_claims` (~129 tokens)

Search across all published OOS claims on OTP. Use natural language queries to find coordination patterns, failure modes, agent rules, and operational intelligence from other organizations.

Input parameters:

- `confidence` (string): Filter by confidence level
- `evidence` (string): Filter by evidence type
- `industry` (string): Filter by industry
- `limit` (number): Results per page (max 100)
- `page` (number): Page number
- `q` (string, required): Search query (e.g. 'shared state file coordination', 'agent escalation failure')
- `template` (string): Filter by template

### `get_oos` (~39 tokens)

Get a specific published OOS file by its ID, including organization metadata and file details.

Input parameters:

- `id` (string, required): The OOS file ID

### `get_claims` (~130 tokens)

Get all claims from a specific OOS file. Each claim contains a rule, reasoning (why), failure mode, confidence level, and evidence type. Filter by section, confidence, or evidence type.

Input parameters:

- `confidence` (string): Filter by confidence level
- `evidence` (string): Filter by evidence type
- `oos_id` (string, required): The OOS file ID to get claims from
- `section` (string): Filter by section (e.g. 'core_operating_rules', 'failure_patterns', 'coordination_patterns', 'operational_heuristics', 'human_ai_boundary_conditions')

### `compare_oos` (~79 tokens)

Compare two published OOS files side-by-side. Returns claims unique to each, similar claims, and duplicates. Great for learning what other organizations do differently.

Input parameters:

- `oos_id_a` (string, required): First OOS file ID (typically yours)
- `oos_id_b` (string, required): Second OOS file ID (the one to compare against)

### `search_intelligence` (~124 tokens)

Deep search across the OTP intelligence base with faceted filtering. Returns claims grouped by section, industry, confidence, and evidence type. More powerful than search_claims.

Input parameters:

- `confidence` (string): Filter by confidence
- `evidence` (string): Filter by evidence type
- `industry` (string): Filter by industry
- `limit` (number): Results per page
- `min_quality` (string): Minimum publisher quality tier
- `page` (number): Page number
- `q` (string): Search query
- `section` (string): Filter by claim section

### `get_publishers` (~87 tokens)

Browse organizations that have published OOS files on OTP. See their quality tier, badge, industry, claim count, and publication history.

Input parameters:

- `industry` (string): Filter by industry
- `limit` (number): Results per page
- `min_quality` (string): Minimum quality tier
- `page` (number): Page number
- `template` (string): Filter by template type

### `get_org` (~43 tokens)

Get a specific organization's public profile on OTP, including their published OOS files, quality tier, badge, and stats.

Input parameters:

- `org_id` (string, required): The organization ID

### `get_patterns` (~65 tokens)

Discover coordination patterns that appear across multiple organizations. Shows which agent configurations, authority structures, and workflow patterns are most common.

Input parameters:

- `industry` (string): Filter patterns by industry
- `min_orgs` (number): Minimum number of organizations a pattern must appear in (default 2)

### `get_sections` (~48 tokens)

List all claim sections available on OTP with counts. Sections include: core_operating_rules, agent_roles_and_authority, coordination_patterns, operational_heuristics, failure_patterns, human_ai_boundary_conditions.

### `publish_oos` (~77 tokens)

Publish an Organizational Operating System file to OTP. Requires an API key. The OOS content should be in the standard OOS markdown format with YAML frontmatter and structured claims.

Input parameters:

- `raw_content` (string, required): The full OOS file content in markdown format with YAML frontmatter
- `template` (string, required): The OOS template type

### `my_dashboard` (~52 tokens)

Get your organization's OTP publisher dashboard. Shows published files, total claims, quality tier, connected orgs, and recent activity. Requires API key.

Input parameters:

- `oos_id` (string, required): Your latest OOS file ID

### `discover_intelligence` (~62 tokens)

Run the OTP Scout to discover relevant coordination intelligence from other organizations. Analyzes gaps in your OOS and finds high-quality claims you might want to adopt. Requires API key.

Input parameters:

- `limit` (number): Maximum number of recommendations to discover (default 20)

### `get_inbox` (~109 tokens)

View your intelligence inbox -- recommendations discovered by the Scout. Filter by status (pending, accepted, rejected, adapted) or section. Requires API key.

Input parameters:

- `limit` (number): Results per page (default 20, max 100)
- `offset` (number): Offset for pagination (default 0)
- `section` (string): Filter by claim section (e.g. 'failure_patterns', 'coordination_patterns')
- `status` (string): Filter by recommendation status (default: pending)

### `review_recommendation` (~121 tokens)

Review a recommendation from your inbox. Accept to adopt as-is, reject to dismiss, or adapt to modify the claim for your organization's context. Requires API key.

Input parameters:

- `action` (string, required): Action to take: accept, reject, or adapt
- `adapted_rule` (string): Modified rule text (required when action is 'adapt')
- `adapted_why` (string): Modified reasoning text (optional when action is 'adapt')
- `id` (string, required): The recommendation ID to review
- `notes` (string): Optional review notes explaining your decision

### `get_inbox_stats` (~43 tokens)

Get a summary of your intelligence inbox -- how many recommendations are pending, accepted, rejected, and adapted. Shows top sections and average relevance score. Requires API key.

### `get_best_practices` (~169 tokens)

Browse OTP's best practices library -- 1,500+ actionable rules from 9 publishers (Google, AWS, Deloitte, Accenture, etc.). Search by keyword, filter by category or publisher. Each practice is a prescriptive rule with why and failure mode. Requires API key.

Input parameters:

- `category` (string): Filter by category (e.g. 'Machine Learning', 'MLOps', 'AI Strategy', 'Prompt Engineering', 'AI Governance')
- `limit` (number): Results per page (default 50, max 200)
- `page` (number): Page number (default 1)
- `publisher` (string): Filter by publisher profile ID
- `q` (string): Search query (e.g. 'prompt engineering', 'data governance', 'agent coordination')

### `get_my_rules` (~119 tokens)

Get your organization's operational rules from OTP -- your published OOS claims PLUS matched best practices from the library. Returns rules in a format agents can directly use for coordination. This is the bridge between OTP and your agent army. Requires API key.

Input parameters:

- `include_best_practices` (boolean): Include matched best practices alongside OOS claims (default true)
- `min_confidence` (string): Minimum confidence level (default: all)
- `section` (string): Filter by section (e.g. 'core_operating_rules', 'coordination_patterns')

### `export_rules_markdown` (~92 tokens)

Export your OTP rules (OOS claims + matched best practices) to a local markdown file that agents can read at startup. This bridges OTP intelligence into your local agent army. Requires API key.

Input parameters:

- `include_best_practices` (boolean): Include matched best practices (default true)
- `output_path` (string): File path to write rules to (default: ~/.claude/otp-rules.md)

### `capture_learning` (~237 tokens)

Capture an operational learning when an agent fails or you discover a better approach. This is the core OTP feedback loop: agent fails → you correct → correction becomes coordination intelligence → all agents improve. The learning is saved as a claim in your draft OOS and will be available via get_my_rules.

Input parameters:

- `agent` (string): Which agent failed. E.g. 'Dash', 'Pepper', 'Dirk'
- `section` (string): Which OOS section this belongs in (auto-detected if not specified)
- `source_url` (string): URL to a better approach, repo, or reference. E.g. 'https://github.com/user/better-meta-analysis'
- `what_failed` (string, required): What went wrong. E.g. 'Dash gave bad Meta Ads analysis -- used wrong date range and missed spend anomalies'
- `what_to_do` (string, required): The rule/fix. E.g. 'Always validate date ranges against the campaign's actual active period before running spend analysis'
- `why` (string): Why this matters. E.g. 'Without date validation, the analysis includes pre-launch zeros that skew averages down'

### `get_network_learnings` (~83 tokens)

See what other organizations on the OTP network have learned recently. Shows operational corrections and coordination discoveries from other agent teams. This is how your agents learn from the entire network, not just your own experience.

Input parameters:

- `agent` (string): Filter by agent name to see learnings relevant to a specific agent
- `limit` (number): Max results (default 20)

### `submit_ticket` (~113 tokens)

Report a bug, request a feature, or ask a question about the OTP platform. Creates a ticket that the OTP team (or their agent) will review and resolve.

Input parameters:

- `category` (string): Ticket category (default: bug)
- `description` (string, required): Detailed description: steps to reproduce, expected behavior, actual behavior
- `priority` (string): Priority level (default: medium)
- `reporter_email` (string): Email for follow-up (optional)
- `title` (string, required): Brief description of the issue

### `list_connections` (~106 tokens)

List the outside systems this organization has connected (Slack, Gmail, Linear, spreadsheets and so on) with the live state of each: active, still authorizing, failed, or disconnected. Each entry carries a plain explanation of what went wrong when something is not working. Use this whenever someone asks what is connected, why a connection is not working, or what you can currently reach. This is the source of truth about connections -- do not infer them from which tools you happen to have.

### `search_integrations` (~139 tokens)

Search the catalog of outside systems that can be connected to OTP (over 1000 apps via Composio). Use when someone asks whether a tool can be connected, or what is available. `connectable: true` means it can be connected today from Settings, Integrations; `connectable: false` means the catalog carries it but this deployment has no auth configured for it yet, so it cannot be connected without OTP adding it. `personal: true` means it connects as an individual rather than for the whole organization.

Input parameters:

- `search` (string, required): What to look for, e.g. 'linear', 'calendar', 'analytics'

### `composio_docs` (~122 tokens)

Search Composio's official documentation (docs.composio.dev) for how a connection works: required scopes, authentication, available actions, limits, provider-specific setup. Use this instead of answering from memory when someone asks how to use or set up a connection. Every result carries the source URL -- cite it.

Input parameters:

- `limit` (number): How many doc pages to return (1-10, default 5)
- `q` (string, required): What to look up, e.g. 'slack scopes', 'connect google calendar', 'trigger webhooks'

### `list_tickets` (~74 tokens)

List tickets on the OTP platform. Filter by status (open, in_progress, resolved, closed) or category (bug, feature, question, other).

Input parameters:

- `category` (string): Filter by category
- `limit` (number): Results per page (max 100)
- `status` (string): Filter by status

### `update_ticket` (~91 tokens)

Update a ticket on OTP. Use to resolve issues, add agent notes, or change status. Requires API key.

Input parameters:

- `agent_notes` (string): Internal notes from the fixing agent
- `id` (string, required): The ticket ID to update
- `priority` (string): New priority
- `resolution` (string): Resolution description (what was done to fix it)
- `status` (string): New status

### `list_my_kpis` (~199 tokens)

List KPIs (scorecard measurables) on the org chart, filterable by owner, each with its goal and its latest recorded value, the period that value is for, and whether it meets the goal. Use this to see what an agent or human is being measured against, which KPIs are off goal, and to find a KPI's id or exact title before pushing a value with update_kpi. latest_value is null when nothing was recorded recently; meets_goal is null when there is no value or no goal.

Input parameters:

- `include_values` (boolean): Attach latest_value, latest_period_start and meets_goal. Default true; pass false for the bare list.
- `owner_entity_type` (string): Filter by entity type.
- `owner_external_id` (string): Filter to one owner's KPIs. E.g. 'AGT_DIRK' for the Dirk agent, 'HUM_DAVIDSTEEL' for David.

### `update_kpi` (~220 tokens)

Push a KPI value (the actual measured number for a period). This is how an agent reports 'this is what I did this week / this month' to its scorecard. Looks up the KPI by title under a given owner, then writes the value. periodStart defaults to the start of the current period for the KPI's time grain (e.g. start of this week for a weekly KPI).

Input parameters:

- `notes` (string): Optional context. E.g. 'after 12pm send wave'.
- `owner_external_id` (string, required): The agent or human external id that owns the KPI. E.g. 'AGT_DIRK'.
- `period_start` (string): ISO date for the period start (YYYY-MM-DD). If omitted, computes start of current period from the KPI's time grain.
- `title` (string, required): The KPI title (case-insensitive match against the KPI's stored title). E.g. 'Cold emails sent'.
- `value` (number, required): The actual measured value for the period. E.g. 30.

### `list_rocks` (~163 tokens)

List quarterly rocks for the authenticated organization. Filter by quarter (e.g. '2026-Q2') or owner_external_id. Each rock carries status: on_track, off_track, completed or archived. Read status, not the on_track flag: a completed rock can still carry on_track false from before it was finished. Archived rocks are left out unless include_archived is true.

Input parameters:

- `include_archived` (boolean): Also return archived rocks. Default false.
- `on_track` (boolean): Only open rocks that are on track (true) or off track (false); completed and archived rocks are excluded
- `owner_external_id` (string): Filter to one owner
- `quarter` (string): Quarter filter, e.g. '2026-Q2'

### `add_rock` (~167 tokens)

Create a quarterly rock: the 90-day priority a seat commits to. Requires owner, title, quarter, and due date.

Input parameters:

- `description` (string)
- `due_date` (string, required): ISO 8601 datetime, e.g. '2026-06-30T23:59:59Z'
- `on_track` (boolean): Defaults to true at creation
- `owner_entity_type` (string, required): Who owns this rock
- `owner_external_id` (string, required): Owner identifier (e.g. 'dsteel', 'dirk')
- `owner_name` (string): Display name for the owner
- `quarter` (string, required): e.g. '2026-Q2'
- `status_note` (string): Initial status note
- `title` (string, required)

### `update_rock` (~73 tokens)

Update a rock's status (on_track flag, status note, completion). Used during the weekly Delta Meeting rock review.

Input parameters:

- `completed` (boolean): Mark rock complete
- `on_track` (boolean)
- `rock_id` (string, required)
- `status_note` (string): Free-text update from the owner

### `get_operating_plan` (~62 tokens)

Read the organization's active Operating Plan (the workspace at /dashboard/oos-operating-plan): the plan, its eight strategy sections with their content, and the current quarter's execution items. Use this before update_operating_plan_section to see what is already there.

### `update_operating_plan_section` (~152 tokens)

Update fields in one section of the organization's active Operating Plan. Provide the section_key and ONLY the fields to change; fields you do not name are preserved (merge, never replace). Common fields: foundation = purpose, mission, values (the core values, one per line), ideal_customer; destination = year_target, ten_year_target, revenue_goal, profit_goal, defining_metric; annual_game_plan = primary_objective, strategic_initiatives, key_outcomes. List-like fields are newline-separated strings.

Input parameters:

- `fields` (object, required): Field key -> new value, only the fields to change. List-like fields take one entry per line.
- `section_key` (string, required): Which strategy section to update

### `list_change_requests` (~103 tokens)

See the changes you asked someone else to approve. When you try to change a to-do, number, priority, project or issue that belongs to a seat your person does not hold, OTP does not apply it: it sends the owner a request and the change waits. This lists those requests with their status: pending, applied (approved and done), declined, failed (approved but could not be applied) or expired (7 days, no answer). Requires API key.

### `list_todos` (~109 tokens)

List 7-day to-dos (commitments made in a Delta Meeting). Filter by open=true to see only incomplete, by meeting_id, or by owner. A to-do that is a copy of a repeating series carries `repeat` with a plain-English `summary` and its `seriesId`.

Input parameters:

- `meeting_id` (string): Only to-dos created in a specific meeting
- `open` (boolean): Only return incomplete to-dos
- `owner_external_id` (string)

### `list_people` (~56 tokens)

Everyone in this organization a to-do can be assigned to (people and AI agents) and its teams, each with the identifier add_todo and update_todo take. Use it to put each action item on the person who owns it.

### `add_todo` (~393 tokens)

Create a to-do (typically a 7-day commitment from a Delta Meeting). Put it on the person who will do it: pass their name as owner_name and OTP finds them (or owner_external_id from list_people). Never write a person's name into the title, e.g. "[Owen Cartier] ..."; the owner is a field, and a to-do filed under the wrong person lands on the wrong person's list. To share one to-do between several people, pass also_assign. Pass `repeat` to make it a repeating to-do: daily, weekly, monthly, yearly or a custom cadence, advancing when each copy is done or on a fixed schedule, with an optional end. The response's todo is the first copy.

Input parameters:

- `also_assign` (array): More people who share this one to-do, by name. Each ticks off their own part.
- `description` (string)
- `due_at` (string): ISO 8601 datetime; defaults to 7 days from now if omitted
- `meeting_id` (string): Meeting in which this to-do was created
- `owner_entity_type` (string): Worked out from the owner; only needed with an id OTP does not know.
- `owner_external_id` (string): The owner's id from list_people. Only needed when two people share a name.
- `owner_name` (string): Who owns it, by name ("Owen Cartier", or a first name only one person has). Enough on its own.
- `repeat` (object): Make this a repeating to-do. Omit for a one-off.
- `team` (string): The team it belongs to, by name or id (list_people lists teams). Defaults to the meeting's team when meeting_id is given. A to-do with a team shows on that team's view.
- `title` (string, required): What needs to happen. No owner name in brackets.

### `update_todo` (~182 tokens)

Change a to-do: its title, description, due date or priority, who it is on, or its team. `assign_to` replaces the people on it (the first is the primary owner); each is a name or a list_people id. Use it to hand a to-do to the person who owns it. Only the fields you pass change.

Input parameters:

- `assign_to` (array): Who it should be on, by name or id. Replaces the current set.
- `description` (string)
- `due_at` (string|null): ISO 8601 datetime, or null to clear the date.
- `priority` (string)
- `team` (string): Move it to a team, by name or id; "none" makes it a personal to-do.
- `title` (string)
- `todo_id` (string, required)

### `complete_todo` (~61 tokens)

Mark a to-do as done (or undone if already complete). For a repeating to-do the response's `nextCopy` is the copy just created, if the series produced one.

Input parameters:

- `done` (boolean)
- `todo_id` (string, required)

### `set_todo_repeat` (~115 tokens)

Make a to-do repeat, change how a repeating to-do repeats, or stop it. Copies already finished or overdue keep their dates.

Input parameters:

- `repeat` (object): The new repeat settings. A one-off becomes a series; a series gets the new settings from here on.
- `stop` (boolean): true: stop the series. This copy stays as a normal to-do; copies already made ahead of their date are removed.
- `todo_id` (string, required): The to-do, or any copy of a repeating series.

### `list_meetings` (~208 tokens)

List Delta Meetings for the authenticated organization, newest first, as summary rows: id, title, when, type, status, team, and whether a transcript and a summary exist. Filter by meeting_type or status; with neither, every type is returned. To find the NEXT meeting, pass upcoming=true: only meetings scheduled from now on, soonest first (newest-first plus a limit would otherwise show the furthest-out recurring instances and miss this week's). This tool deliberately does NOT return transcripts or notes -- call get_meeting_transcript or get_meeting_agenda with an id from here for the contents of one meeting.

Input parameters:

- `limit` (integer): How many meetings to return. Defaults to 25.
- `meeting_type` (string): e.g. 'leadership', 'departmental', '1on1'
- `status` (string)
- `upcoming` (boolean): Only meetings scheduled from now on, soonest first. Use this to find the next meeting.

### `create_meeting` (~130 tokens)

Schedule a new Delta Meeting. Returns the meeting object including its ID and the URL of the running meeting page. Pass team_id to put it on a specific team, or team_id null for a personal meeting on no team; omit it and it lands on the organization's default team.

Input parameters:

- `attendees` (array)
- `meeting_type` (string)
- `scheduled_at` (string, required): ISO 8601 datetime
- `team_id`: Team the meeting belongs to. Omit for the org's default team; pass null for a personal meeting on no team.
- `title` (string, required)

### `get_meeting_agenda` (~156 tokens)

Get one meeting's agenda: the meeting itself, the scorecard snapshot (with each KPI's latest value), the rocks snapshot, OPEN issues (status open or in_progress) and OPEN to-dos, trimmed to the fields an agenda needs, plus counts of the closed and done items left out. Issues and to-dos are the organization's, not filtered to the meeting's team. Pass include_closed=true to also get recently resolved issues and done to-dos. Use to prep, render or summarize a meeting.

Input parameters:

- `include_closed` (boolean): Also return resolved/closed issues and done to-dos (the 100 most recent of each). Default false: open items only.
- `meeting_id` (string, required)

### `get_meeting_transcript` (~206 tokens)

Read a meeting's transcript -- what was actually said in the room. Use this whenever someone asks about the CONTENT of a meeting: what was decided, who said what, what a number was, what someone committed to. get_meeting_agenda returns a meeting's structure; this returns its words. Long transcripts arrive one window at a time -- if next_offset comes back there is more, so keep reading before you answer. When has_transcript is false, say plainly that no transcript is attached rather than guessing at what was said. This tool is off unless the organization's Owner has enabled transcript reading; if it refuses, relay that plainly and say the Owner can turn it on in Settings, Redaction. Never imply the refusal is a bug or that you can work around it.

Input parameters:

- `meeting_id` (string, required)
- `offset` (integer): Character offset to read from. Omit to start at the beginning; pass the next_offset from the previous call to continue.

### `start_meeting` (~41 tokens)

Start a Delta Meeting -- snapshots current scorecard and rocks into the meeting record so the agenda is frozen at meeting time.

Input parameters:

- `meeting_id` (string, required)

### `end_meeting` (~30 tokens)

End a Delta Meeting. Marks status complete and stamps endedAt.

Input parameters:

- `meeting_id` (string, required)

### `list_whiteboards` (~134 tokens)

List the organization's whiteboards -- shared visual canvases where people sketch and arrange sticky notes together, sometimes alongside a meeting. Returns each board's id, title, status ('draft', 'active', or 'filed'), the meeting it is attached to if any, who created it, and when it last changed. Filter by status, or by meeting_id to find the board a specific meeting used. This is the index only; use read_whiteboard to see what is written on a board.

Input parameters:

- `meeting_id` (string): Only boards attached to this meeting
- `status` (string): Only boards in this state

### `read_whiteboard` (~161 tokens)

Read what is currently written on a whiteboard: the text of its sticky notes and shapes, grouped by frame, as a plain-text outline. This is the CURRENT contents of a live collaborative canvas that people may still be editing -- not a finished document, and not a history of what the board used to say. Only text comes through: drawings, arrows, and images have nothing to extract, so a busy-looking board can honestly come back sparse. When note_count is 0, say the board has no readable text rather than guessing at what is drawn on it. Find a board's id with list_whiteboards. Very large boards are cut off; `truncated` tells you when.

Input parameters:

- `whiteboard_id` (string, required): From list_whiteboards

### `add_issue` (~350 tokens)

Raise an issue on this organization's own issues list, where it lands on the issues board and on the Issues section of that team's Delta Meeting. Use this when someone wants something on the agenda: a problem to work through, a decision to make, a topic to raise. Pass team_id to put it in front of a specific team's meeting -- get it from list_meetings, which returns each meeting's teamId; omit it and the issue is org-wide and unassigned, which is a real state, not a failure. This is the org's OWN issue list. To report a bug or request a feature FROM the OTP vendor, use submit_ticket instead -- the two look similar and go to completely different places.

Input parameters:

- `category` (string): Default 'other', which is what an agenda item usually is
- `description` (string): Detail, if the person gave any. Do NOT invent one: leave it out and the issue records where it came from instead.
- `horizon` (string): 'short' (default) is worked day to day; 'long' parks it for the quarterly.
- `owner_entity_type` (string)
- `owner_external_id` (string): Seat that owns the issue, e.g. 'HUM_DAVIDSTEEL' or 'AGT_RADAR'
- `owner_name` (string)
- `priority` (string): Default medium
- `team_id`: Team whose meeting should show this issue, from list_meetings' teamId. Omit or pass null for an org-wide issue on no team.
- `title` (string, required): The issue as the person said it, e.g. 'Feedback for customers wanting to cancel'

### `set_issue_status` (~84 tokens)

Move an issue (ticket) through the identify, discuss and solve lifecycle. Optionally rank an issue (priorityRank=1 means top priority).

Input parameters:

- `ids_status` (string)
- `priority_rank`
- `resolution` (string): Solution captured when moving to 'solved'
- `solved_in_meeting_id`
- `ticket_id` (string, required)

### `list_processes` (~125 tokens)

List this organization's processes (SOPs written on agent seats) together with any schedules already attached to them. Use this BEFORE creating, changing, or running a schedule: it is the only place the real agent externalId and SOP title come from, and both are required by the other process tools. The response also tells you whether autonomous runs are currently armed for the deployment (schedulerArmed) and whether this org is allowed to schedule at all (gate). Never guess an externalId or a SOP title; if this returns nothing, the org has no processes to schedule yet.

### `create_schedule` (~359 tokens)

Schedule a process to run automatically on a recurring cadence -- hourly, daily, or weekly -- in a named timezone. This is real autonomy: once created and enabled, OTP runs the SOP on its own and the run spends the organization's wallet, with no human in the session. Call list_processes first and pass the exact agent_external_id and sop_title it returned. Cadence is limited to hourly/daily/weekly by design; there is no raw cron and no weekdays-only option, so say so plainly rather than approximating one. Requires a funded wallet and an active API key.

Input parameters:

- `agent_external_id` (string, required): The seat that owns the process, exactly as list_processes returned it (e.g. 'AGT_RADAR')
- `cadence` (string, required): How often it runs
- `hour` (integer): Hour of day, 0-23, in the schedule's timezone. Required for daily and weekly; ignored for hourly. 10 means 10am.
- `minute` (integer): Minute of the hour, 0-59. Defaults to 0.
- `name` (string): Label for the schedule. Defaults to the SOP title.
- `sop_id` (string): SOP id when list_processes returned one; more precise than matching on title
- `sop_title` (string, required): Exact title of the SOP to run, as list_processes returned it
- `timezone` (string): IANA timezone the hour is read in, e.g. 'America/New_York'. Defaults to America/New_York. Ask rather than assume when the user's timezone is not already known.
- `weekday` (integer): Day of week for weekly, 0=Sunday through 6=Saturday. Defaults to Monday.

### `update_schedule` (~176 tokens)

Change an existing schedule: pause it (enabled=false), resume it (enabled=true), or move when it runs. Pausing is the right answer when someone wants a schedule to stop for now; deleting throws away the setup. Any cadence field left out keeps its current value, so moving a daily run from 9am to 10am needs only hour=10. Get the schedule id from list_processes.

Input parameters:

- `cadence` (string)
- `enabled` (boolean): false pauses the schedule, true resumes it
- `hour` (integer)
- `minute` (integer)
- `schedule_id` (string, required): Schedule id from list_processes
- `timezone` (string): IANA timezone, e.g. 'America/New_York'
- `weekday` (integer): 0=Sunday through 6=Saturday

### `delete_schedule` (~66 tokens)

Delete a schedule permanently. Prefer update_schedule with enabled=false when the intent is 'stop it for now' -- a pause is reversible in one click and a delete is not. Get the schedule id from list_processes.

Input parameters:

- `schedule_id` (string, required): Schedule id from list_processes

### `run_process` (~130 tokens)

Run a process once, right now, instead of waiting for its schedule. The run spends the organization's wallet. Use this when someone wants the result immediately, or wants to see what a process produces before committing it to a schedule -- running it once first is usually the better order. Call list_processes for the exact agent externalId and SOP title.

Input parameters:

- `agent_external_id` (string, required): The seat that owns the process, from list_processes
- `sop_id` (string): SOP id when list_processes returned one
- `sop_title` (string, required): Exact SOP title, from list_processes

### `my_coaching` (~191 tokens)

What needs attention for the person asking: observations OTP has computed about the seats they hold, each with the suggested next actions attached. Returns only their own seats -- never a colleague's, never a direct report's. Answers with what the evaluation engine actually wrote; if it has not run there is nothing to report and the tool says so rather than estimating. ALSO returns openQuestions: things only this person can tell OTP, which it cannot observe. When any are present, say which part of the picture is missing and ask ONE of them conversationally at the end of your answer -- never a list, never all of them, and never before you have answered what they actually asked. Record the reply with answer_coaching_question.

Input parameters:

- `question` (string): The person's question in their own words, e.g. 'what should I fix first?'. Steers what to lead with; never changes what exists.

### `approve_coaching_action` (~80 tokens)

Approve one suggested action and carry it out -- creating the to-do, issue, measurable or meeting exactly as it was shown. The approving seat is taken from the caller's own session, never from arguments. Only ever call this after the person has seen the proposal and said yes.

Input parameters:

- `intervention_id` (string, required): The intervention the person approved

### `decline_coaching_action` (~82 tokens)

Decline a suggested action, with the reason in the person's own words. Declining the suggestion is not the same as dismissing the observation -- the underlying finding stays, and Ollie may offer a different way in.

Input parameters:

- `intervention_id` (string, required)
- `reason` (string, required): Why, in their words. A refusal with no reason teaches nothing.

### `set_coaching_disposition` (~159 tokens)

Record what the person decided about an observation itself. 'snoozed' goes quiet until a date. 'dismissed' goes quiet for 90 days and returns quoting their reason back. 'not_our_way' means this is genuinely not how this team works and the check never raises it for that seat again. 'acted_on' means they handled it. Use this whenever somebody says a suggestion is not relevant -- it is how Ollie learns to stop.

Input parameters:

- `finding_id` (string, required)
- `reason` (string): Required for 'dismissed' and 'not_our_way'
- `snoozed_until` (string): ISO date; required for 'snoozed'
- `state` (string, required)

### `my_coaching_questions` (~101 tokens)

The handful of questions only this person can answer about their own seat -- whether they are clear on what they own, whether they could describe where the organization is going, whether the recurring work is done the same way everyone else does it. OTP cannot observe any of that, so it asks. Returns only unanswered questions for the current period, and only for seats the caller holds. Ask these conversationally, one at a time, and never all at once.

### `answer_coaching_question` (~155 tokens)

Record the person's own answer about their own seat: yes, partly, or no, plus anything they said in their own words. 'partly' is a real answer and usually the most useful one -- do not round it to yes or no. Only ever call this with what they actually said; never infer an answer from tone or from what they said about something else.

Input parameters:

- `check_key` (string, required): From my_coaching_questions
- `check_version` (integer, required): From my_coaching_questions
- `note` (string): Their own words, verbatim where possible
- `response` (string, required)
- `seat_external_id` (string, required): The seat the question is about; must be one the caller holds

## Diagnostics

Captured diagnostic sections: Provenance, Dependencies. The full working is on the page: https://verifymcp.io/servers/david-steel-otp/otp-mcp-server#diagnostics

## Score history

- 2026-11-05: 62
- 2026-11-04: 62
- 2026-11-03: 62
- 2026-11-02: 62
- 2026-11-01: 62
- 2026-10-31: 62
- 2026-10-30: 47

## Common questions

### What is the OTP MCP server?

OTP is an MCP server listed in the public MCP registry as io.github.david-steel/otp. Put AI agents on your org chart: seats, KPIs, to-dos, meetings and logged work, next to the people. This page covers its npm package (otp-mcp-server).

### Is the OTP MCP server safe to use?

OTP scores 62 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 5 November 2026. It declares no install or post-install scripts. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the OTP MCP server expose?

OTP exposes 66 tools: register_agent, claim_seat, get_my_seat, log_work, browse_oos, and 61 more. Their descriptions and schemas cost roughly 8,900 tokens of context every time the server is loaded.

### Is the OTP MCP server still maintained?

OTP is still listed as active in the MCP registry. We last reached this channel on 5 November 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

### What licence is the OTP MCP server under?

OTP declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.

### What did VerifyMCP test on the OTP MCP server?

VerifyMCP ran 14 checks on OTP, covering Malware scan, Known CVEs, Install scripts, Dependency health and 10 more. 2 items could not be completed, a gap on our side rather than a finding about OTP: Security disclosure and Stability. One category scores 0 for that reason, because we only credit what we can confirm. Endpoint Security and Transport & Reachability do not apply to an npm package, so they were not tested. The score does not measure everything, and the scoring documentation lists what it leaves out.

## Links

- npm package: https://www.npmjs.com/package/otp-mcp-server
- Socket report: https://socket.dev/npm/package/otp-mcp-server
- Website: https://orgtp.com/
- Changelog RSS feed: https://verifymcp.io/servers/david-steel-otp/otp-mcp-server.xml
- Changelog JSON feed: https://verifymcp.io/servers/david-steel-otp/otp-mcp-server/changelog.json
- Trust report (JSON): https://verifymcp.io/servers/david-steel-otp/otp-mcp-server.json
- HTML version of this page: https://verifymcp.io/servers/david-steel-otp/otp-mcp-server
