# Openpulse for agents

> Two ways in: an MCP server at `https://openpulse.cloud/mcp` for assistants, and a REST API
> under `https://openpulse.cloud/v1` for programs. Both read one workspace's own data and both
> need credentials a workspace admin creates.

Generated at build time from the same constants the product enforces. Nothing below
is aspirational, and no scope, prefix or path here is a copy of one kept elsewhere.

## MCP server

- **Endpoint**: `https://openpulse.cloud/mcp`, streamable HTTP.
- **Server card**: [`/.well-known/mcp/server-card.json`](https://openpulse.cloud/.well-known/mcp/server-card.json)
- **Authentication**: OAuth 2.1. This is a *resource server only*: it verifies bearer
  tokens and issues none. An unauthenticated request returns `401` with a
  `WWW-Authenticate` header pointing at the protected-resource metadata below, which
  names the authorization server to register with.
- **Protected resource metadata**: [`/.well-known/oauth-protected-resource`](https://openpulse.cloud/.well-known/oauth-protected-resource)
- **Authorization server metadata**: [`/.well-known/oauth-authorization-server`](https://openpulse.cloud/.well-known/oauth-authorization-server)

Call `tools/list` for the tool surface, then `get_usage_guide` before anything
non-trivial: the valid signal classifications differ per listener mode, and filtering
by one from the wrong mode returns an empty list rather than an error.

The tools are read-only apart from rating a signal and queueing a run. An agent can
never create, change or delete a listener: a listener commits the workspace to
recurring search and model spend on every schedule tick.

## REST API

- **Base**: `https://openpulse.cloud/v1`
- **Authentication**: `Authorization: Bearer op_live_…`, a key created in
  workspace settings.
- **Status**: [`/health`](https://openpulse.cloud/health)

A key always acts as a **member, never an admin**. Privilege comes from scopes, and
the scope vocabulary has no way to express an admin action: a leaked key can read
signals and move deals, and can never create a listener, change billing, or mint
another key.

| Scope | Grants |
| --- | --- |
| `signals:read` | List and read signals, their scores and their reasoning. |
| `accounts:read` | List companies and what has been found about them. |
| `pipeline:read` | List deals, their stages and the return figures. |
| `pipeline:write` | Add deals and move them between stages. |
| `collections:write` | Save signals to lists, and write notes. |
| `export:read` | Download the CSV exports. Filtered only: a key is never an admin. |

A route that declares no scope is unreachable by a key. That is default-deny by
construction rather than by review, so a route added tomorrow is not published to
every key in existence the moment it merges.

## Boundaries

- Only publicly available results are ingested. Openpulse does not log in to any
  platform and does not bypass access controls.
- Neither interface reaches any workspace but the one the credential belongs to.
- Rate limits are per workspace and are returned in the response rather than
  documented here, where they would go stale.

## See also

- [`/auth.md`](https://openpulse.cloud/auth.md): how an agent registers and what a credential is.
- [`/llms-full.txt`](https://openpulse.cloud/llms-full.txt): the whole product, as one document.
- [`/.well-known/api-catalog`](https://openpulse.cloud/.well-known/api-catalog): this page, as a linkset.
- [Contact](mailto:support@openpulse.cloud): a real address, answered by people.
