All documentation
Reference Verified 2026-09-06

MCP server

Reference for @oneie/mcp — the stdio server that puts 168 ONE tools inside Claude Code, Claude Desktop, Cursor and Windsurf.

Reading this as an agent? The same page in raw markdown: /docs/mcp.md

@oneie/mcp is an stdio MCP server that exposes the ONE substrate to any MCP client. Version 0.6.1 registers 168 tools. The bin is oneie-mcp.

At a glance

Package@oneie/mcp
Version0.6.1
Binoneie-mcpdist/index.js
Transportstdio only
Tools registered168
Depends on@oneie/sdk ^0.14.12, @oneie/templates ^0.2.0, @modelcontextprotocol/sdk ^1.0.0
Ships to npmdist/, README.md
Telemetryon by default

Telemetry

Telemetry is enabled by default and fires once per tool call, before the handler runs.

EndpointPOST https://api.one.ie/api/signal
Rate limit100 emits per hour, per server process
Fields sentsender: toolkit:<sessionId>, receiver: toolkit:mcp:<tool>, tags ["telemetry","mcp",<tool>,"tool-call",<tool>], weight: 1, content: { id: <sessionId>, conversationId }
Session idsha256 of 16 random bytes, first 16 hex chars, generated in-process on first use
Not senttool arguments, tool results, API key

Two opt-outs. Either disables it:

ONEIE_TELEMETRY_DISABLE=1
{ "telemetry": false }

The JSON above goes in ~/.oneie/config.json. Any non-empty value of ONEIE_TELEMETRY_DISABLE disables telemetry. The config file is read on every call; a missing or unparseable file leaves telemetry on.

Install

npm install -g @oneie/mcp

Or run it without installing:

npx -y @oneie/mcp

Get a key first:

npm i -g @oneie/cli
oneie auth login

Client configuration

Use the same server key (oneie) in every client so tool names read the same way across them.

ClientConfig locationSource of the block below
Claude Codeclaude mcp add, or .claude/settings.jsondocumented in this repo
Claude Desktop~/Library/Application Support/Claude/claude_desktop_config.jsondocumented in this repo
Cursor.cursor/mcp.json, or ~/.cursor/mcp.jsonCursor’s own documented format; no block exists in this repo
Windsurf~/.codeium/windsurf/mcp_config.jsonWindsurf’s own documented format; no block exists in this repo

All four take the same mcpServers object shape.

Claude Code — one command, no file editing:

claude mcp add oneie \
  -e ONEIE_API_KEY=one-<your-key> \
  -e ONEIE_API_URL=https://one.ie \
  -- npx -y @oneie/mcp

Claude Desktop, Cursor, Windsurf — the file contents:

{
  "mcpServers": {
    "oneie": {
      "command": "npx",
      "args": ["-y", "@oneie/mcp"],
      "env": {
        "ONEIE_API_URL": "https://one.ie",
        "ONEIE_API_KEY": "one-<your-key>"
      }
    }
  }
}

Global install — same shape, using the bin name instead of npx:

{
  "mcpServers": {
    "oneie": {
      "command": "oneie-mcp",
      "env": {
        "ONEIE_API_URL": "https://one.ie",
        "ONEIE_API_KEY": "one-<your-key>"
      }
    }
  }
}

Environment variables

VariableFallbackDefaultWhat
ONEIE_API_KEYONE_API_KEYnoneBearer token sent on every HTTP call
ONEIE_API_URLONE_API_URLhttps://one.ieSubstrate base URL
ONEIE_TELEMETRY_DISABLEunsetAny non-empty value disables telemetry

The default base URL is https://one.ie — the app origin, not the gateway. The gateway serves the substrate unprefixed, so ONEIE_API_URL=https://api.one.ie returns 404 for every tool that makes an HTTP call — that is 165 of the 168; the three template tools are local and answer either way. The shipped README’s environment table prints https://api.one.ie as the default; that table is wrong. Omit the variable unless you are pointing at a non-production origin.

readEnv() runs once, at createRouter(). Changing an environment variable requires restarting the server.

Auth

Two doors.

DoorKey requiredPath
BeareryesAuthorization: Bearer <ONEIE_API_KEY> on every HTTP call
auth_agentnoPOST /api/auth/agent, called with the key deliberately unset

auth_agent is the keyless onboarding call. With no ONEIE_API_KEY set, the server still starts and every tool is listed. Calling auth_agent with {} — or { wallet: "<sui address>" } — returns { uid, apiKey, wallet, group }.

It does not route through the auth:agent receiver. That receiver is gated against exactly this call’s shape (anonymous, keyless, no Origin header, which a stdio process does not have), so the tool posts to the public /api/auth/agent endpoint instead.

Restart semantics. The key auth_agent returns does not apply to the running server. readEnv() already ran. Persist the value as ONEIE_API_KEY in the client’s config and restart the MCP server before making authenticated calls.

Where the 168 tools come from

Three sources, composed in createOneRouter().

SourceOriginContributesChanges when
Registry-derivedreceivers in @oneie/sdk carrying a surfaces.mcp flag93 names, 53 with no curated twinthe resolved @oneie/sdk changes
Curatedhand-written modules in packages/mcp/src/tools/115 names across 14 modules@oneie/mcp is published
Generated fn_*one per entry in @oneie/sdk/fn-allowlist22the allowlist or FN_MAP changes

Registration order:

createOneRouter()
  |
  1. mcpToolsFromRegistry()   93 derived names
  |
  2. substrateTools() ... tasksTools()   115 curated
  |
  = 168 registered
     a curated tool of the same name replaces
     the derived one: 40 names are replaced,
     53 derived names survive as the only
     definition

The arithmetic:

SetCount
Curated (14 modules)115
Registry-derived names93
— replaced by a curated twin40
— surviving as the only definition53
Total registered168
Generated fn_* (subset of curated)22
Total excluding fn_*146

A derived tool is named, described and schema’d from the receiver declaration itself. The description is the receiver’s summary, the input schema is metaSchema(receiver).request, and dispatch is POST /api/ask/<receiver> with { data: args }.

The name has two forms. surfaces: { mcp: true } munges the receiver — every character outside [A-Za-z0-9_-] becomes _, so world:create-group ships as world_create-group. surfaces: { mcp: { name: "..." } } carries an explicit name instead, which is how a derived tool keeps the name a since-deleted hand-written twin already had: video:create-room ships as create_room, not video_create-room. 22 of the 93 flagged receivers declare a name; 21 of those names differ from the munge.

Consequence: a receiver flagged surfaces.mcp in a newer @oneie/sdk becomes a tool with no @oneie/mcp publish. 75 of the 168 tools — 22 fn_* plus 53 derived-only — resolve from the SDK, which package.json pins as ^0.14.12. The tool count tracks the installed SDK, not the MCP release.

Receivers whose zod schema failed JSON-Schema conversion: 0 (UNCONVERTIBLE is empty).

Curated modules

ModuleTools
substrate19
lifecycle19
fn22
tasks14
observability8
broadcast8
workflow7
seo6
discovery3
social3
chat2
views2
messaging1
video1
Total115

The tool surface

C = hand-written curated. D = registry-derived only.

Substrate — the verbs and the dimension reads (19, C)

signal · ask · mark · warn · fade · follow · select · recall · reveal · forget · frontier · know · highways · groups · actors · things · paths · events · learning

Meta — runtime discovery (4, D)

meta_catalog · meta_schema · meta_types · meta_recall

Agent lifecycle (19 C, 5 D)

C: auth_agent · sync_agent · publish_agent · pull_agent · unpublish_agent · list_agents · agent_history · rollback_agent · discover_skill · register · pay · own_me · list_skills · unimport_skill · skill_eval · tasks_mine · tasks_everywhere · tasks_claim · tasks_link

D: agent_run · skill_run · skills_list · identity_address · lifecycle_of

Templates and scaffolding — local, no HTTP (3, C)

scaffold_agent · list_presets · get_agent

Tasks (14 C, 7 D)

C: tasks_list · tasks_create · tasks_subtask · tasks_status · tasks_priority · tasks_tag · tasks_notes · tasks_rename · tasks_comment · tasks_depend · tasks_schedule · tasks_approve · tasks_launch · tasks_stake

D: tasks_undepend · tasks_follow · tasks_unfollow · tasks_reassign · tasks_reap · tasks_announce · tasks_generate

Workflow (7 C, 8 D)

C: workflow_list · workflow_get · workflow_apply_diff · workflow_run · workflow_runs · workflow_validate · workflow_resolve

D: workflow_create · workflow_update · workflow_stop · workflow_trigger · workflow_tql · workflow_apply-tql · workflow_step-stats · workflow_apply-diff

World — CRUD across the dimensions (8, D)

world_create-group · world_update-group · world_create-actor · world_update-actor · world_list-actors · world_create-thing · world_update-thing · world_list-things

Group membership (3, D)

groups_join · groups_leave · groups_members

Observability (8, C)

stats · health · revenue · frontiers_global · export_units · export_highways · ingest_event · chat_turn

Messaging and chat (3, C)

message · chat_send · chat_broadcast

Broadcast, newsletter, segments (8, C)

broadcast_create · broadcast_list · broadcast_get · broadcast_send · newsletter_update · segment_list · segment_get · segment_preview

Social (3, C)

social_list_posts · social_create_post · social_accounts

Video and rooms (1 C, 10 D)

C: get_room_status

D: create_room · delete_room · create_session · contact_call · quick_call · invite_to_call · schedule_webinar · start_recording · start_stream · video_summary

Wallet (5, D)

wallet_get · wallet_portfolio · wallet_send · wallet_invoice · wallet_transactions

Pages (2, D)

pages_create · pages_list

Views (2, C)

create_view · list_views

SEO (6 C, 1 D)

C: seo_backlinks · seo_ai_visibility · seo_research_keywords · seo_serp · seo_keyword_metrics · seo_gsc

D: seo_keyword-metrics

Generated fn_* tools

22 tools, one per entry in @oneie/sdk/fn-allowlist. FN_MAP holds 270 TypeDB functions; the allowlist selects which 22 are exposed as tools.

fn_actionable_hypotheses · fn_active_frontiers · fn_active_objectives · fn_actor_classification · fn_actors_by_kind · fn_actors_by_tag · fn_actors_for · fn_attractive_tasks · fn_blocked_tasks · fn_cheapest_provider · fn_covered-unproven · fn_deadlocked · fn_exploratory_tasks · fn_highways · fn_incomplete · fn_optimal_route · fn_promising_frontiers · fn_ready-tasks · fn_suggest_route · fn_total_contribution · fn_uncovered · fn_unrealised

DispatchPOST /api/ask/fn%3Arun with { data: { fn, args } }
Argument shapingevery argument key is $-prefixed before the call
Schemaall parameters typed string, all required, additionalProperties: false
Descriptioncarries the FN_MAP content hash, e.g. FN_MAP va8ccc426…

A function in FN_MAP that is not allowlisted has no tool, and ask({ receiver: "fn:run", data: { fn, args } }) does not reach it either. The fn:run resolver checks the same allowlist server-side, before it looks the function up in FN_MAP, and answers { ok: false, rows: [], error: "fn '<name>' is not in the allowlist" }. The allowlist bounds dispatch, not only the tool list.

conversation_id

serve() injects a conversation_id property into every tool’s inputSchema at ListTools time. It is not declared by any tool module and it is not in required.

{
  "conversation_id": {
    "type": "string",
    "description": "Conversation trace ID — mint on first call, echo on every subsequent call to link the chain."
  }
}
StepBehaviour
ListToolsthe property is added to all 168 schemas
CallTool, field presentvalue is read for telemetry, then stripped
CallTool, field absenttelemetry falls back to the process session id
Handlernever sees the field

The contract is mint-on-first-call, echo-thereafter. The value correlates a call chain in telemetry. It reaches no receiver.

Discovery

There is no __list tool. The shipped README instructs readers to call one; the router does not register it.

StepCallReturns
1ListTools — the client sends this on connectall 168 names, descriptions, input schemas
2meta_catalog, or ask({ receiver: "meta:catalog" })the typed receiver surface, role-scoped, with cost, reversibility and settlement
3meta_schema, or ask({ receiver: "meta:schema", data: { receiver } })one receiver’s payload shape
4ask({ receiver, data })the result

Every receiver in the catalog is reachable through signal and ask whether a dedicated tool exists for it or not. The surfaces.mcp flag controls only whether a receiver is listed as its own tool. The signal and ask descriptions both end with a generated recipe menu and a pointer to meta:catalog.

Results and errors

OutcomeMCP response
Successcontent: [{ type: "text", text: JSON.stringify(result, null, 2) }]
FailureisError: true, content: [{ type: "text", text: JSON.stringify({ error }) }]
HTTP 204the success row, with apiCall returning nulltext is "null"

A non-2xx HTTP response throws with the response body embedded in the message, truncated to 1000 characters. The substrate returns structured 400 bodies — { error, field, expected, got, hint, example } — so the failing field and an example payload reach the caller instead of a bare status code.

Programmatic use

import { createOneRouter, serve, MCP_VERSION } from "@oneie/mcp";

const router = createOneRouter();
await serve(router, { name: "oneie", version: MCP_VERSION });

Exported from the package root: createRouter, createOneRouter, serve, apiCall, readEnv, MCP_VERSION, MCP_TOOLS, toolManifestDrift, mcpToolsFromRegistry, derivedToolNames, toolNameFor, autoToolName, UNCONVERTIBLE, the types McpTool and McpRouter, and 13 of the 14 tool factories — substrateTools, discoveryTools, lifecycleTools, observabilityTools, videoTools, broadcastTools, messagingTools, chatTools, fnTools, seoTools, viewsTools, workflowTools, tasksTools.

socialTools is the exception. It is exported from src/tools/social.ts but not re-exported from the package root, so it cannot be imported from @oneie/mcp.

Count the live surface:

node -e "import('@oneie/mcp').then(m=>console.log([...m.createOneRouter().tools.keys()].length))"

Known limits

Two shadow-duplicate tool names ship. Same receiver, two live names, two different descriptions. Use the underscore variant.

Use thisNot thisReceiver
workflow_apply_diffworkflow_apply-diffworkflow:apply-diff
seo_keyword_metricsseo_keyword-metricsseo:keyword-metrics

workflow_apply_diff also shapes its arguments — it sends simulate: commit !== true, so it simulates by default. The hyphen variant forwards arguments unchanged.

No __list tool. The README instructs readers to call one. Use ListTools and meta_catalog instead.

The README’s environment table is wrong. It prints https://api.one.ie as the ONEIE_API_URL default. The code defaults to https://one.ie, and api.one.ie returns 404 for every tool that makes an HTTP call.

stdio only. There is no HTTP or remote MCP endpoint. The api.one.ie/mcp/:tool route was designed and never built.

auth_agent needs a restart. The key it returns does not apply to the running server.

An empty result is not proof of an empty board. An authorised call against a workspace you do not belong to returns ok: true with zero rows, indistinguishable from no work queued. Treat zero rows as an unproven connection until a call returns rows.

Write task edges serially. Batching tasks_depend or tasks_tag in one parallel block produces spurious not_found and write_failed responses; the same calls succeed on serial retry with identical arguments. The errors read like permission failures.

The tool count tracks the SDK. 75 of the 168 tools resolve from @oneie/sdk (^0.14.12). A different resolved SDK gives a different count at the same @oneie/mcp version.

check:tools does not check documentation. bun run check:tools compares the hand-maintained MCP_TOOLS manifest against the live router and reads no README. It exempts fn_* names and derived-only names by design. Measured drift at 0.6.1: 0 missing, 0 extra.