{
  "openapi": "3.1.0",
  "info": {
    "title": "NepoNet tools API",
    "version": "1.0.0",
    "summary": "Warm-intro routes on X, for agents",
    "description": "NepoNet finds the warmest chain of introductions from you to anyone on X, explains every step, drafts the first ask, and tracks your outreach. It never sends anything for you.\n\nThe same tools as the MCP server at https://nepotism.network/mcp. Send a JSON object of the tool's arguments; the answer is JSON.",
    "contact": {
      "url": "https://nepotism.network/agents"
    },
    "termsOfService": "https://nepotism.network/terms"
  },
  "externalDocs": {
    "url": "https://nepotism.network/llms-full.txt",
    "description": "Full reference for agents"
  },
  "servers": [
    {
      "url": "https://nepotism.network/api/v1"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "paths": {
    "/tools": {
      "get": {
        "operationId": "listTools",
        "summary": "Every tool, with its JSON Schema, permission and hints",
        "security": [],
        "responses": {
          "200": {
            "description": "The tools",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/tools/whoami": {
      "post": {
        "operationId": "whoami",
        "summary": "Who am I",
        "description": "Start here. The signed-in person: their X handle (every route starts from it), plan, searches left today, whether they've written a brief, how far reading their own network has got, and which permissions this connection has.",
        "tags": [
          "account"
        ],
        "x-neponet-scope": null,
        "x-neponet-effect": "read",
        "x-mcp-annotations": {
          "title": "Who am I",
          "readOnlyHint": true,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": false
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {},
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/connect_x": {
      "post": {
        "operationId": "connectX",
        "summary": "Connect an X account",
        "description": "Sets the X account every route starts from, by handle, and starts reading who follows it and whom it follows. Only for the person's own account: ask them for it rather than guessing. Not needed when whoami already shows one.",
        "tags": [
          "routes"
        ],
        "x-neponet-scope": "routes:search",
        "x-neponet-effect": "write",
        "x-mcp-annotations": {
          "title": "Connect an X account",
          "readOnlyHint": false,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": true
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "routes:search"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "handle": {
                    "type": "string",
                    "description": "Their own X handle, with or without the @"
                  }
                },
                "required": [
                  "handle"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/get_brief": {
      "post": {
        "operationId": "getBrief",
        "summary": "Read the brief",
        "description": "What this person is working on, in their own words: who they are, what they're building, what an intro should lead to, and what they can offer in return. Read this before drafting anything; it is the only sanctioned source for claims about them.",
        "tags": [
          "brief"
        ],
        "x-neponet-scope": "brief:read",
        "x-neponet-effect": "read",
        "x-mcp-annotations": {
          "title": "Read the brief",
          "readOnlyHint": true,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": false
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "brief:read"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {},
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/set_brief": {
      "post": {
        "operationId": "setBrief",
        "summary": "Update the brief",
        "description": "Writes the fields given and leaves the rest alone. Only record what the person actually said about themselves.",
        "tags": [
          "brief"
        ],
        "x-neponet-scope": "brief:write",
        "x-neponet-effect": "write",
        "x-mcp-annotations": {
          "title": "Update the brief",
          "readOnlyHint": false,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": false
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "brief:write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "about": {
                    "type": "string",
                    "description": "Who they are, in their own words"
                  },
                  "building": {
                    "type": "string",
                    "description": "What they're building; this replaces [YOUR PRODUCT] in drafts"
                  },
                  "askingFor": {
                    "type": "string",
                    "description": "What an intro should lead to: a call, a beta user, an investor conversation"
                  },
                  "offering": {
                    "type": "string",
                    "description": "What they bring, so the ask isn't one-sided"
                  },
                  "tone": {
                    "type": "string",
                    "enum": [
                      "warm",
                      "direct",
                      "formal"
                    ],
                    "description": "How their messages should read"
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/find_person": {
      "post": {
        "operationId": "findPerson",
        "summary": "Find someone on X",
        "description": "Searches indexed accounts by handle, and X's own suggestions for names. Use this to turn a name (\"Paul Graham\") into a handle before anything else, and confirm with the person when several match. Costs nothing.",
        "tags": [
          "graph"
        ],
        "x-neponet-scope": "graph:read",
        "x-neponet-effect": "read",
        "x-mcp-annotations": {
          "title": "Find someone on X",
          "readOnlyHint": true,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": true
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "graph:read"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "query": {
                    "type": "string",
                    "description": "A handle or a name"
                  }
                },
                "required": [
                  "query"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/get_person": {
      "post": {
        "operationId": "getPerson",
        "summary": "Read a profile",
        "description": "Everything indexed about one account: profile, counts, the profiles they link to elsewhere, and how they relate to the person asking.",
        "tags": [
          "graph"
        ],
        "x-neponet-scope": "graph:read",
        "x-neponet-effect": "read",
        "x-mcp-annotations": {
          "title": "Read a profile",
          "readOnlyHint": true,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": true
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "graph:read"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "handle": {
                    "type": "string",
                    "description": "Their X handle, with or without the @"
                  }
                },
                "required": [
                  "handle"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/get_dossier": {
      "post": {
        "operationId": "getDossier",
        "summary": "What research found about someone",
        "description": "What a search's research read about one person: what they work on, what they talk about, how they write, and a couple of their own posts verbatim. The summary lines are leads and may be wrong; only `quotes` are their own words and may be repeated back to them. Returns null when nobody has researched them yet, which is an ordinary answer and not an error.",
        "tags": [
          "graph"
        ],
        "x-neponet-scope": "graph:read",
        "x-neponet-effect": "read",
        "x-mcp-annotations": {
          "title": "What research found about someone",
          "readOnlyHint": true,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": false
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "graph:read"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "handle": {
                    "type": "string",
                    "description": "Their X handle, with or without the @"
                  }
                },
                "required": [
                  "handle"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/list_paths": {
      "post": {
        "operationId": "listPaths",
        "summary": "Known chains to someone",
        "description": "The warmest chain to someone from what is already indexed, without crawling X and without spending anything. Always try this before start_search: if it answers, the search would only confirm it.",
        "tags": [
          "routes"
        ],
        "x-neponet-scope": "routes:read",
        "x-neponet-effect": "read",
        "x-mcp-annotations": {
          "title": "Known chains to someone",
          "readOnlyHint": true,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": false
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "routes:read"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "handle": {
                    "type": "string",
                    "description": "Who they want to reach"
                  }
                },
                "required": [
                  "handle"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/start_search": {
      "post": {
        "operationId": "startSearch",
        "summary": "Search for intro routes",
        "description": "Finds the warmest chains of intros to someone, reading X in the background. This spends one of their searches for the day (searching the same person again is free) and takes a few minutes. Call list_paths first, confirm the target with the person, then call this and follow it with wait_for_search.",
        "tags": [
          "routes"
        ],
        "x-neponet-scope": "routes:search",
        "x-neponet-effect": "spend",
        "x-mcp-annotations": {
          "title": "Search for intro routes",
          "readOnlyHint": false,
          "destructiveHint": false,
          "idempotentHint": false,
          "openWorldHint": true
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "routes:search"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "handle": {
                    "type": "string",
                    "description": "Who they want to reach"
                  },
                  "budget": {
                    "type": "string",
                    "enum": [
                      "quick",
                      "standard",
                      "deep"
                    ],
                    "description": "How hard to look. standard is the default; quick is enough for a well-connected target; deep needs Premium."
                  },
                  "goal": {
                    "type": "string",
                    "description": "Why this person, in one line. Saved with the target and used when drafting the ask."
                  }
                },
                "required": [
                  "handle"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/wait_for_search": {
      "post": {
        "operationId": "waitForSearch",
        "summary": "Wait for a search",
        "description": "Waits up to timeoutSeconds for a running search to finish, then returns a short digest: status, progress, the top routes as one line each, and what to do next. Call it again while `finished` is false. Cheaper than get_search for following progress.",
        "tags": [
          "routes"
        ],
        "x-neponet-scope": "routes:read",
        "x-neponet-effect": "read",
        "x-mcp-annotations": {
          "title": "Wait for a search",
          "readOnlyHint": true,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": false
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "routes:read"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "searchId": {
                    "type": "integer",
                    "description": "The search's id, from start_search or list_searches"
                  },
                  "timeoutSeconds": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 55,
                    "description": "How long to wait, 0-55. Default 25."
                  },
                  "until": {
                    "type": "string",
                    "enum": [
                      "finished",
                      "any_route"
                    ],
                    "description": "Return when the search finishes (default), or as soon as it has any route."
                  }
                },
                "required": [
                  "searchId"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/get_search": {
      "post": {
        "operationId": "getSearch",
        "summary": "Read a search",
        "description": "Everything known about one target: the ranked routes with each step explained, who to befriend first, what has already been asked, the goal and the brief. This is the whole context for planning an approach — prefer it over calling several smaller tools. Pass detail \"summary\" for just progress and the routes in one line each.",
        "tags": [
          "routes"
        ],
        "x-neponet-scope": "routes:read",
        "x-neponet-effect": "read",
        "x-mcp-annotations": {
          "title": "Read a search",
          "readOnlyHint": true,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": false
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "routes:read"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "searchId": {
                    "type": "integer",
                    "description": "The search's id, from start_search or list_searches"
                  },
                  "detail": {
                    "type": "string",
                    "enum": [
                      "full",
                      "summary"
                    ],
                    "description": "full (default) is the planning bundle; summary is a few hundred tokens."
                  }
                },
                "required": [
                  "searchId"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/list_searches": {
      "post": {
        "operationId": "listSearches",
        "summary": "Past searches",
        "description": "Targets this person has searched from their current handle, newest first, with how many routes each found.",
        "tags": [
          "routes"
        ],
        "x-neponet-scope": "routes:read",
        "x-neponet-effect": "read",
        "x-mcp-annotations": {
          "title": "Past searches",
          "readOnlyHint": true,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": false
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "routes:read"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 50,
                    "description": "1 to 50, default 20"
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/stop_search": {
      "post": {
        "operationId": "stopSearch",
        "summary": "Stop a search",
        "description": "Stops a running search and drops the lists it still had queued. The routes found so far stay. Starting the same target again later is free.",
        "tags": [
          "routes"
        ],
        "x-neponet-scope": "routes:search",
        "x-neponet-effect": "write",
        "x-mcp-annotations": {
          "title": "Stop a search",
          "readOnlyHint": false,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": false
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "routes:search"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "searchId": {
                    "type": "integer",
                    "description": "The search's id, from start_search or list_searches"
                  }
                },
                "required": [
                  "searchId"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/suggest_bridges": {
      "post": {
        "operationId": "suggestBridges",
        "summary": "Who to befriend first",
        "description": "People who would open a warmer route if they and this person followed each other, each with the evidence behind it. Useful when every route is cold or there are none.",
        "tags": [
          "routes"
        ],
        "x-neponet-scope": "routes:read",
        "x-neponet-effect": "read",
        "x-mcp-annotations": {
          "title": "Who to befriend first",
          "readOnlyHint": true,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": false
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "routes:read"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "searchId": {
                    "type": "integer",
                    "description": "The search's id, from start_search or list_searches"
                  }
                },
                "required": [
                  "searchId"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/draft_intro_ask": {
      "post": {
        "operationId": "draftIntroAsk",
        "summary": "Facts for drafting an ask",
        "description": "Everything needed to write the first message on a route, and nothing more: who to ask, what each person in the chain would be doing, the tie behind every step, the brief, and any message already saved. Write the message yourself from these facts — do not assert anything about a person that isn't here — and show it to the person; they send it themselves.",
        "tags": [
          "routes"
        ],
        "x-neponet-scope": "routes:read",
        "x-neponet-effect": "read",
        "x-mcp-annotations": {
          "title": "Facts for drafting an ask",
          "readOnlyHint": true,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": false
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "routes:read"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "searchId": {
                    "type": "integer",
                    "description": "The search's id, from start_search or list_searches"
                  },
                  "routeId": {
                    "type": "string",
                    "description": "Which route; defaults to the warmest"
                  }
                },
                "required": [
                  "searchId"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/set_goal": {
      "post": {
        "operationId": "setGoal",
        "summary": "Say why this target",
        "description": "Saves one line on why the person wants to reach a search's target (\"raise our seed round\", \"hire them as an advisor\"). It is the single thing that most improves drafts and plans. Pass an empty goal to clear it.",
        "tags": [
          "outreach"
        ],
        "x-neponet-scope": "outreach:write",
        "x-neponet-effect": "write",
        "x-mcp-annotations": {
          "title": "Say why this target",
          "readOnlyHint": false,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": false
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "outreach:write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "searchId": {
                    "type": "integer",
                    "description": "The search's id, from start_search or list_searches"
                  },
                  "goal": {
                    "type": "string",
                    "description": "One or two lines, at most 300 characters"
                  }
                },
                "required": [
                  "searchId",
                  "goal"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/list_outreach": {
      "post": {
        "operationId": "listOutreach",
        "summary": "The outreach board",
        "description": "Who this person is planning to ask or has asked, and what happened.",
        "tags": [
          "outreach"
        ],
        "x-neponet-scope": "outreach:read",
        "x-neponet-effect": "read",
        "x-mcp-annotations": {
          "title": "The outreach board",
          "readOnlyHint": true,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": false
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "outreach:read"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "targetHandle": {
                    "type": "string",
                    "description": "Only outreach toward this person"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "to_ask",
                      "asked",
                      "introduced",
                      "replied",
                      "declined"
                    ],
                    "description": "Only items in this state"
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/record_outreach": {
      "post": {
        "operationId": "recordOutreach",
        "summary": "Track someone to ask",
        "description": "Adds a person to the outreach board for a target, or updates them if already there. This records an intention — NepoNet never sends anything, so the person still has to send the message themselves.",
        "tags": [
          "outreach"
        ],
        "x-neponet-scope": "outreach:write",
        "x-neponet-effect": "write",
        "x-mcp-annotations": {
          "title": "Track someone to ask",
          "readOnlyHint": false,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": false
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "outreach:write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "targetHandle": {
                    "type": "string",
                    "description": "Who they're ultimately trying to reach"
                  },
                  "personHandle": {
                    "type": "string",
                    "description": "Who to ask"
                  },
                  "searchId": {
                    "type": "integer",
                    "description": "The search this came from, if any"
                  },
                  "routeId": {
                    "type": "string",
                    "description": "The route this came from, if any"
                  },
                  "step": {
                    "type": "integer",
                    "description": "Which ask in the chain this person makes, 1-based"
                  },
                  "steps": {
                    "type": "integer",
                    "description": "How many asks the chain has"
                  },
                  "detail": {
                    "type": "string",
                    "description": "What this person does, e.g. \"Introduces you\""
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "to_ask",
                      "asked",
                      "introduced",
                      "replied",
                      "declined"
                    ]
                  },
                  "message": {
                    "type": "string",
                    "description": "The drafted message, for the person to send themselves"
                  }
                },
                "required": [
                  "targetHandle",
                  "personHandle"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/update_outreach": {
      "post": {
        "operationId": "updateOutreach",
        "summary": "Update an outreach item",
        "description": "Changes the state, the saved message or the note on one person already on the board: mark someone asked once the person says they sent it, introduced or replied when they hear back, declined if it went nowhere.",
        "tags": [
          "outreach"
        ],
        "x-neponet-scope": "outreach:write",
        "x-neponet-effect": "write",
        "x-mcp-annotations": {
          "title": "Update an outreach item",
          "readOnlyHint": false,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": false
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "outreach:write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "integer",
                    "description": "From list_outreach or record_outreach"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "to_ask",
                      "asked",
                      "introduced",
                      "replied",
                      "declined"
                    ]
                  },
                  "message": {
                    "type": "string",
                    "description": "The drafted message"
                  },
                  "note": {
                    "type": "string",
                    "description": "A private note"
                  }
                },
                "required": [
                  "id"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/delete_outreach": {
      "post": {
        "operationId": "deleteOutreach",
        "summary": "Remove from the outreach board",
        "description": "Removes one person from the outreach board, with its saved message and note. Confirm with the person first; this can't be undone.",
        "tags": [
          "outreach"
        ],
        "x-neponet-scope": "outreach:write",
        "x-neponet-effect": "write",
        "x-mcp-annotations": {
          "title": "Remove from the outreach board",
          "readOnlyHint": false,
          "destructiveHint": true,
          "idempotentHint": true,
          "openWorldHint": false
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "outreach:write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "integer",
                    "description": "From list_outreach"
                  }
                },
                "required": [
                  "id"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/list_plans": {
      "post": {
        "operationId": "listPlans",
        "summary": "Written plans",
        "description": "Every target with a written plan, newest first: who it's for, who it goes through, the ask, and how many steps are done.",
        "tags": [
          "plans"
        ],
        "x-neponet-scope": "plans:read",
        "x-neponet-effect": "read",
        "x-mcp-annotations": {
          "title": "Written plans",
          "readOnlyHint": true,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": false
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "plans:read"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {},
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/get_plan": {
      "post": {
        "operationId": "getPlan",
        "summary": "Read a plan",
        "description": "One written plan: which route, the ask, and every step with who to message, when, and the drafts (with the person's own edits). Pass planId, or searchId for that search's newest plan.",
        "tags": [
          "plans"
        ],
        "x-neponet-scope": "plans:read",
        "x-neponet-effect": "read",
        "x-mcp-annotations": {
          "title": "Read a plan",
          "readOnlyHint": true,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": false
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "plans:read"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "planId": {
                    "type": "integer",
                    "description": "From list_plans or get_research"
                  },
                  "searchId": {
                    "type": "integer",
                    "description": "Instead of planId: the newest plan for this search"
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/update_plan_step": {
      "post": {
        "operationId": "updatePlanStep",
        "summary": "Tick off a plan step",
        "description": "Records what the person did with one step: pick a draft, save their edit of it, add a note, or mark it done or skipped. Marking a message step done also puts that person on the outreach board as asked. Only mark done once the person says they sent it.",
        "tags": [
          "plans"
        ],
        "x-neponet-scope": "plans:write",
        "x-neponet-effect": "write",
        "x-mcp-annotations": {
          "title": "Tick off a plan step",
          "readOnlyHint": false,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": false
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "plans:write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "planId": {
                    "type": "integer",
                    "description": "From get_plan"
                  },
                  "stepKey": {
                    "type": "string",
                    "description": "The step's key, from get_plan"
                  },
                  "state": {
                    "type": "string",
                    "enum": [
                      "todo",
                      "done",
                      "skipped"
                    ],
                    "description": "todo, done or skipped"
                  },
                  "chosenDraft": {
                    "type": "integer",
                    "description": "Index of the draft they picked"
                  },
                  "edit": {
                    "type": "object",
                    "description": "Their rewrite of one draft",
                    "properties": {
                      "index": {
                        "type": "integer"
                      },
                      "text": {
                        "type": "string",
                        "maxLength": 4000
                      }
                    },
                    "required": [
                      "index",
                      "text"
                    ],
                    "additionalProperties": false
                  },
                  "note": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "A private note, or null to clear it"
                  }
                },
                "required": [
                  "planId",
                  "stepKey"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/research_and_plan": {
      "post": {
        "operationId": "researchAndPlan",
        "summary": "Research and write a plan",
        "description": "Reads up on the person, the target and everyone on the routes (recent posts, the pages they link), then writes a plan with drafts for every message. Runs in the background for a few minutes on the AI account the person connected to NepoNet, which bills them. Only when they ask for it; otherwise write the plan yourself from get_search. Follow with get_research.",
        "tags": [
          "plans"
        ],
        "x-neponet-scope": "plans:write",
        "x-neponet-effect": "spend",
        "x-mcp-annotations": {
          "title": "Research and write a plan",
          "readOnlyHint": false,
          "destructiveHint": false,
          "idempotentHint": false,
          "openWorldHint": true
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "plans:write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "searchId": {
                    "type": "integer",
                    "description": "The search's id, from start_search or list_searches"
                  }
                },
                "required": [
                  "searchId"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools/get_research": {
      "post": {
        "operationId": "getResearch",
        "summary": "Follow research",
        "description": "Where a research job is, optionally waiting up to waitSeconds for it to finish. When it's done, planId names the plan it wrote.",
        "tags": [
          "plans"
        ],
        "x-neponet-scope": "plans:read",
        "x-neponet-effect": "read",
        "x-mcp-annotations": {
          "title": "Follow research",
          "readOnlyHint": true,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": false
        },
        "security": [
          {
            "apiKey": []
          },
          {
            "oauth": [
              "plans:read"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "jobId": {
                    "type": "integer",
                    "description": "From research_and_plan"
                  },
                  "waitSeconds": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 55,
                    "description": "How long to wait for it to finish, 0-55. Default 0."
                  }
                },
                "required": [
                  "jobId"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The arguments were wrong; `error` says which",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Out of searches (`quota_exceeded`) or a budget that needs Premium",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "This key doesn't have the permission (`insufficient_scope`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such tool, search, plan or item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Something has to happen first, e.g. `x_required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; `retryAfter` is in seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "What went wrong, and what to do about it"
          },
          "code": {
            "type": "string",
            "description": "Machine-readable reason, e.g. quota_exceeded or insufficient_scope"
          }
        },
        "required": [
          "error"
        ]
      }
    },
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key (npn_sk_…) from https://nepotism.network/?view=account, or an OAuth access token."
      },
      "oauth": {
        "type": "oauth2",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://nepotism.network/api/oauth/authorize",
            "tokenUrl": "https://nepotism.network/api/oauth/token",
            "refreshUrl": "https://nepotism.network/api/oauth/token",
            "scopes": {
              "graph:read": "Look people up and read their profiles",
              "routes:read": "Read the intro routes your searches found",
              "routes:search": "Start new searches — spends your daily search quota and reads X",
              "outreach:read": "Read who you've asked and what happened",
              "outreach:write": "Add and update people on your outreach board",
              "brief:read": "Read what you're working on",
              "brief:write": "Change what you're working on",
              "plans:read": "Read your written plans and drafts",
              "plans:write": "Tick off plan steps, and research and write new plans with your connected AI account"
            }
          }
        }
      }
    }
  }
}