# MCP Core Tools Contract Date: 2026-07-09 ## Route statement 项目核心不是继续做 UIA selector/report,而是通过 MCP 暴露 iSphere 的联系人、群组、消息、文件能力。 This contract defines the business-facing MCP tool surface. The existing `win_helper_*` tools remain low-level auxiliary tools for controlled read-only observation and fallback implementation work. They are not the product API. ## Hard boundaries - No automatic login. - No permission bypass. - No process injection, hook, target-process memory read, credential extraction, or endpoint-security bypass. - Search contacts, search groups, receive messages, and receive files should be implemented read-only first. - Real message sending and file sending require `approval_id`. - Without `approval_id`, write-capable tools must stay in `dry_run=true` behavior and must not send. - Every real write must produce an audit record with target, content/file hash, approver, timestamp, source connector, and result. - UIA selectors are allowed only as fallback access mechanics after higher-priority sources are exhausted or unavailable. ## Common error codes | Code | Meaning | | --- | --- | | `INVALID_ARGUMENT` | Required parameter missing or invalid. | | `SOURCE_UNAVAILABLE` | Selected bridge/API/database/UIA source is unavailable. | | `NOT_LOGGED_IN` | A required manually logged-in client session is not present. | | `PERMISSION_DENIED` | Current operator/account is not authorized for the requested object. | | `APPROVAL_REQUIRED` | A real write was requested without valid approval. | | `DRY_RUN_ONLY` | Tool is currently limited to dry-run behavior. | | `TARGET_NOT_FOUND` | Contact, group, conversation, message, or file was not found. | | `AMBIGUOUS_TARGET` | Multiple possible targets match and the request must be narrowed. | | `TIMEOUT` | The connector did not complete before timeout. | | `CONNECTOR_FAILED` | Underlying source or helper returned a structured failure. | | `INTERNAL_ERROR` | Unexpected implementation error. | ## Common audit fields Every tool response should include an `audit` object: ```json { "tool": "isphere_search_contacts", "request_id": "uuid", "source": "bridge|local_readonly|uia|network|mock", "operator_id": "optional operator identity", "approval_id": null, "dry_run": false, "target_ref": "optional stable target reference", "content_sha256": null, "file_sha256": null, "started_at": "ISO-8601", "finished_at": "ISO-8601", "result": "ok|error" } ``` ## Tool: `isphere_search_contacts` | Field | Value | | --- | --- | | Business purpose | Search authorized iSphere contacts so a digital employee can resolve a person before reading or drafting work. | | Read-only | Yes. | | Requires `approval_id` | No. | | Supports `dry_run` | Not required; optional `dry_run` may return the planned query only. | | Current priority | Stage C read-only loop, first priority. | Input parameters: ```json { "query": "string, required", "limit": "integer, optional, default 20, max 100", "cursor": "string, optional", "source_preference": "bridge|local_readonly|uia|network|auto, optional, default auto", "include_inactive": "boolean, optional, default false" } ``` Output JSON: ```json { "ok": true, "contacts": [ { "contact_id": "string", "display_name": "string", "account": "string|null", "department": "string|null", "title": "string|null", "source": "bridge|local_readonly|uia|network|mock", "confidence": 0.98, "raw_ref": "redacted source reference" } ], "next_cursor": null, "audit": {} } ``` Errors: `INVALID_ARGUMENT`, `SOURCE_UNAVAILABLE`, `NOT_LOGGED_IN`, `PERMISSION_DENIED`, `TIMEOUT`, `CONNECTOR_FAILED`, `INTERNAL_ERROR`. ## Tool: `isphere_search_groups` | Field | Value | | --- | --- | | Business purpose | Search authorized iSphere groups so a digital employee can resolve a group conversation before reading or drafting work. | | Read-only | Yes. | | Requires `approval_id` | No. | | Supports `dry_run` | Not required; optional `dry_run` may return the planned query only. | | Current priority | Stage C read-only loop, first priority. | Input parameters: ```json { "query": "string, required", "limit": "integer, optional, default 20, max 100", "cursor": "string, optional", "source_preference": "bridge|local_readonly|uia|network|auto, optional, default auto", "include_archived": "boolean, optional, default false" } ``` Output JSON: ```json { "ok": true, "groups": [ { "group_id": "string", "display_name": "string", "member_count": "integer|null", "owner_ref": "string|null", "source": "bridge|local_readonly|uia|network|mock", "confidence": 0.96, "raw_ref": "redacted source reference" } ], "next_cursor": null, "audit": {} } ``` Errors: `INVALID_ARGUMENT`, `SOURCE_UNAVAILABLE`, `NOT_LOGGED_IN`, `PERMISSION_DENIED`, `TIMEOUT`, `CONNECTOR_FAILED`, `INTERNAL_ERROR`. ## Tool: `isphere_receive_messages` | Field | Value | | --- | --- | | Business purpose | Read authorized recent messages and normalize them for digital employee reasoning and drafting. | | Read-only | Yes. | | Requires `approval_id` | No. | | Supports `dry_run` | Optional; if true, returns source/query plan without message bodies. | | Current priority | Stage C read-only loop, first priority after contact/group source discovery. | Input parameters: ```json { "conversation_id": "string, optional when query is supplied", "conversation_type": "direct|group|system|unknown, optional", "query": "string, optional target name or keyword", "since": "ISO-8601 timestamp, optional", "limit": "integer, optional, default 50, max 200", "cursor": "string, optional", "include_attachment_metadata": "boolean, optional, default true", "source_preference": "bridge|local_readonly|uia|network|auto, optional, default auto", "dry_run": "boolean, optional, default false" } ``` Output JSON: ```json { "ok": true, "conversation": { "conversation_id": "string", "conversation_type": "direct|group|system", "display_name": "string" }, "messages": [ { "message_id": "string", "sender_id": "string|null", "sender_name": "string|null", "content_type": "text|image|file|rich|notify|unknown", "content_text": "authorized text or redacted summary", "attachments": [ { "file_id": "string", "file_name": "string", "size_bytes": "integer|null", "download_ref": "string|null" } ], "created_at": "ISO-8601|null", "received_at": "ISO-8601|null", "source": "bridge|local_readonly|uia|network|mock", "raw_ref": "redacted source reference" } ], "next_cursor": null, "audit": {} } ``` Errors: `INVALID_ARGUMENT`, `SOURCE_UNAVAILABLE`, `NOT_LOGGED_IN`, `PERMISSION_DENIED`, `TARGET_NOT_FOUND`, `TIMEOUT`, `CONNECTOR_FAILED`, `INTERNAL_ERROR`. ## Tool: `isphere_receive_files` | Field | Value | | --- | --- | | Business purpose | List and receive/download authorized files from messages without mutating the iSphere client state. | | Read-only | Yes for source/client state. It may write downloaded files only to an operator-approved local output directory. | | Requires `approval_id` | No for read-only listing or authorized download. Approval can be added later for sensitive destinations. | | Supports `dry_run` | Yes. `dry_run=true` lists planned files and destination paths without downloading. | | Current priority | Stage C read-only loop after messages expose file metadata. | Implementation note: if the implementation becomes clearer with two internal operations, split into `list_files` and `download_file` behind this business contract. Do not expand the roadmap beyond receive/download. Input parameters: ```json { "conversation_id": "string, optional", "message_id": "string, optional", "file_id": "string, optional for download, omitted for list", "mode": "list|download, optional, default list", "output_dir": "string, optional, required for download", "limit": "integer, optional, default 50, max 200", "cursor": "string, optional", "source_preference": "bridge|local_readonly|uia|network|auto, optional, default auto", "dry_run": "boolean, optional, default true for download" } ``` Output JSON: ```json { "ok": true, "mode": "list|download", "files": [ { "file_id": "string", "message_id": "string|null", "conversation_id": "string|null", "file_name": "string", "size_bytes": "integer|null", "mime_type": "string|null", "created_at": "ISO-8601|null", "download_ref": "string|null", "saved_path": "string|null", "sha256": "string|null", "source": "bridge|local_readonly|uia|network|mock" } ], "next_cursor": null, "audit": {} } ``` Errors: `INVALID_ARGUMENT`, `SOURCE_UNAVAILABLE`, `NOT_LOGGED_IN`, `PERMISSION_DENIED`, `TARGET_NOT_FOUND`, `DRY_RUN_ONLY`, `TIMEOUT`, `CONNECTOR_FAILED`, `INTERNAL_ERROR`. ## Tool: `isphere_send_message` | Field | Value | | --- | --- | | Business purpose | Send an approved text message to a resolved contact or group. | | Read-only | No. | | Requires `approval_id` | Yes for any real send. | | Supports `dry_run` | Yes, required. Default must be `true` until production approval flow is accepted. | | Current priority | Stage D approval-after-read-only loop. | Input parameters: ```json { "target_type": "contact|group|conversation, required", "target_id": "string, required", "content_text": "string, required", "approval_id": "string, required when dry_run=false", "dry_run": "boolean, optional, default true", "idempotency_key": "string, optional but recommended", "source_preference": "bridge|uia|network|auto, optional, default auto" } ``` Output JSON: ```json { "ok": true, "dry_run": true, "send_status": "planned|sent|rejected", "target": { "target_type": "contact|group|conversation", "target_id": "string", "display_name": "string|null" }, "message_ref": null, "content_sha256": "sha256 hex", "audit": {} } ``` Errors: `INVALID_ARGUMENT`, `APPROVAL_REQUIRED`, `PERMISSION_DENIED`, `NOT_LOGGED_IN`, `TARGET_NOT_FOUND`, `AMBIGUOUS_TARGET`, `DRY_RUN_ONLY`, `TIMEOUT`, `CONNECTOR_FAILED`, `INTERNAL_ERROR`. ## Tool: `isphere_send_file` | Field | Value | | --- | --- | | Business purpose | Send an approved local file to a resolved contact or group. | | Read-only | No. | | Requires `approval_id` | Yes for any real send. | | Supports `dry_run` | Yes, required. Default must be `true` until production approval flow is accepted. | | Current priority | Stage D after `isphere_send_message`. | Input parameters: ```json { "target_type": "contact|group|conversation, required", "target_id": "string, required", "file_path": "string, required; must be under an approved outbound directory", "caption": "string, optional", "approval_id": "string, required when dry_run=false", "dry_run": "boolean, optional, default true", "idempotency_key": "string, optional but recommended", "source_preference": "bridge|uia|network|auto, optional, default auto" } ``` Output JSON: ```json { "ok": true, "dry_run": true, "send_status": "planned|sent|rejected", "target": { "target_type": "contact|group|conversation", "target_id": "string", "display_name": "string|null" }, "file_ref": null, "file_sha256": "sha256 hex", "file_size_bytes": 12345, "audit": {} } ``` Errors: `INVALID_ARGUMENT`, `APPROVAL_REQUIRED`, `PERMISSION_DENIED`, `NOT_LOGGED_IN`, `TARGET_NOT_FOUND`, `AMBIGUOUS_TARGET`, `DRY_RUN_ONLY`, `TIMEOUT`, `CONNECTOR_FAILED`, `INTERNAL_ERROR`. ## Stage priority summary | Priority | Tool | Stage | | --- | --- | --- | | 1 | `isphere_search_contacts` | C read-only loop | | 2 | `isphere_search_groups` | C read-only loop | | 3 | `isphere_receive_messages` | C read-only loop | | 4 | `isphere_receive_files` | C read-only loop | | 5 | `isphere_send_message` | D approval-backed write | | 6 | `isphere_send_file` | D approval-backed write |