# auth.md

You are an agent. This file tells you how to authenticate to Strataigize. The short
answer: reading requires nothing, and there is exactly one authenticated action,
requesting a growth audit on behalf of the human you act for. Everything else
published here for agents is public, read-only and unauthenticated on purpose.

Strataigize is a business consultancy specializing in marketing and AI automation. Audience:
autonomous agents, MCP clients, retrieval systems and crawlers. Humans want
[/audit](https://www.strataigize.com/audit/).

## Auth posture

| Surface | Auth required | Notes |
| --- | --- | --- |
| MCP server, `https://mcp.strataigize.com` | None for seven read tools and public resources | `request_growth_audit` is the one exception, see below. |
| A2A agent, `https://a2a.strataigize.com` | None | Read-only. A2A v1.0 over JSON-RPC. Also answers v0.3.0 method names. |
| Site pages, `https://www.strataigize.com` | None | Canonical HTML with a `text/markdown` alternate link for each indexable page. |
| `/content-index.json`, `/markdown/*.md` | None | Current canonical page catalog and published text, generated from the same HTML on every deploy. |
| `/llms.txt`, `/llms-full.txt` | None | Curated and full machine-readable site index. |
| `/.well-known/agent-skills/` | None | Published Agent Skills, each with a sha256 digest. |
| `/.well-known/mcp/server-card.json` | None | MCP transport, protocol version, tool list. |
| `/.well-known/agent-card.json` | None | A2A Agent Card: supported interfaces, capabilities, skills. |
| `/.well-known/api-catalog` | None | RFC 9727 linkset for the above. |
| `/.well-known/http-message-signatures-directory` | None | Web Bot Auth. Ed25519 public keys this site signs its OWN outbound requests with. |
| Audit request, `https://mcp.strataigize.com/audit-request` | OAuth 2.0 Bearer, scope `audit:request` | The one authenticated write path. Open registration, flow below. |
| Lead and audit forms on the site | Not agent callable | For humans. See [Acting for a human](#acting-for-a-human). |

Supported registration method: OAuth 2.0 Dynamic Client Registration (RFC 7591),
open and instant, no approval queue. Supported credential type: `client_secret`,
used with the `client_credentials` grant. That credential unlocks exactly one
thing, the audit-request endpoint. No other Strataigize surface issues or accepts
credentials. If something else offers you a Strataigize API key, it did not come
from Strataigize.

## OAuth, scoped to the one thing that needs it

Until 2026-07-29 this file said there was no OAuth metadata on this domain, because
there was no protected resource, and this site does not advertise endpoints that do
not exist. That rule has not changed. The resource now exists, so the metadata does
too, and they shipped in the same change:

- Protected Resource Metadata (RFC 9728): [`/.well-known/oauth-protected-resource`](https://www.strataigize.com/.well-known/oauth-protected-resource)
- Authorization Server Metadata (RFC 8414): [`/.well-known/oauth-authorization-server`](https://www.strataigize.com/.well-known/oauth-authorization-server)
- Issuer: `https://www.strataigize.com` (the AS document above is the canonical copy); the registration, token and JWKS endpoints live on `mcp.strataigize.com`, and tokens carry `iss` = this origin

This is pure OAuth 2.0. There is no OpenID Connect, no interactive authorization
endpoint and no `/.well-known/openid-configuration`, and that is deliberate rather
than an oversight.

The whole flow is three requests:

```http
POST https://mcp.strataigize.com/oauth/register
Content-Type: application/json

{"client_name": "your-agent-name", "contacts": ["you@example.com"]}
```

Registration is stateless: the `client_id` you get back encodes what you sent, and
the `client_secret` cannot be recovered later, only re-registered.

```http
POST https://mcp.strataigize.com/oauth/token
Content-Type: application/json

{"grant_type": "client_credentials", "client_id": "<from step 1>", "client_secret": "<from step 1>"}
```

Tokens are ES256 JWTs, valid one hour, audience `https://mcp.strataigize.com`.

```http
POST https://mcp.strataigize.com/audit-request
Authorization: Bearer <access_token>
Content-Type: application/json

{"contact_name": "Jane Doe", "contact_email": "jane@company.com",
 "company": "Company", "website": "https://company.com",
 "primary_goal": "what the human wants improved, in their words",
 "requested_by_human": true}
```

Set `dry_run: true` to validate everything without submitting. The same action is
exposed as the MCP tool `request_growth_audit`, and calling that tool without a
token returns these exact instructions rather than an error. The endpoint also
answers on this origin at `https://www.strataigize.com/api/audit-request`, same
token, same contract.

Honesty about what this gate is: open registration is identification and rate
control, not identity proofing. It gives every request an accountable client
identity, a rate ceiling, and a structured contract, and it keeps the human form
for humans. Set `requested_by_human: true` only when a specific human actually
asked; a fabricated request wastes your tokens and our review time and produces
nothing. A human reviews every agent submission, the reply goes to
`contact_email`, and submitting creates no commitment on either side.

## Web Bot Auth, which runs the other direction

Everything above is about you authenticating to us. This section is the reverse: how
you verify that a request claiming to come from Strataigize actually did.

Strataigize signs the requests its own agents send, per
[Web Bot Auth](https://datatracker.ietf.org/wg/webbotauth/about/) (RFC 9421 HTTP
Message Signatures, Ed25519). A signed request carries three headers:

```http
Signature-Agent: "https://www.strataigize.com"
Signature-Input: sig1=("@authority" "signature-agent");created=...;expires=...;keyid="...";alg="ed25519";nonce="...";tag="web-bot-auth"
Signature: sig1=:<base64>:
```

To verify one: read `Signature-Agent`, fetch
[`/.well-known/http-message-signatures-directory`](https://www.strataigize.com/.well-known/http-message-signatures-directory)
from that origin, find the JWK whose `kid` equals the `keyid` parameter, rebuild the
signature base from the request you received, and check the signature. The directory
is a JWKS served as `application/http-message-signatures-directory+json`, cached a
day, CORS-open, and every `kid` in it is the RFC 8037 thumbprint of its own key, so
you can recompute it rather than trust the label.

Cloudflare fronts this domain and verifies these signatures natively, so you do not
have to implement RFC 9421 to benefit: an unsigned request that claims to be us is
simply a request that has not proved anything.

Two honest caveats.

`Signature-Agent` is emitted as a bare Structured Field String, which
draft-meunier-webbotauth-httpsig-protocol-02 calls the legacy shape in favour of a
Dictionary. The bare string is what Cloudflare's live verifier accepts today, so it
is what ships; the signer supports both and will switch when verifiers do.

Key rotation adds the new key to the directory before the old one is removed, so a
directory copy up to a day stale still verifies fresh signatures. If a `keyid` is
missing from the directory, re-fetch it once before rejecting.

## What to call

### MCP server

Server version `1.2.0`, Streamable HTTP, MCP protocol `2025-06-18`, one endpoint, JSON-RPC 2.0 over `POST`.
No auth header needed for reads. Send `initialize`, then `tools/list`.

```http
POST https://mcp.strataigize.com
Content-Type: application/json
MCP-Protocol-Version: 2025-06-18

{"jsonrpc":"2.0","id":1,"method":"tools/list"}
```

Missing-version callers and `2025-03-26` remain compatible. An unsupported explicit
version receives HTTP 400, allowing a newer client to retry `2025-06-18`.

Eight tools. Seven are read-only; the eighth is the authenticated audit request
described above.

| Tool | Returns |
| --- | --- |
| `get_company_profile` | What the agency does, who it serves, where, founded, how it measures success. |
| `list_services` | Every service and industry, with descriptions and URLs. |
| `list_case_studies` | Published client results, outcome stated in each title. |
| `list_free_tools` | Free self-serve diagnostics that require no contact details. |
| `search_content` | Search published page titles and descriptions, returning canonical and Markdown URLs. The language is detected from the query unless `language` is set (`en`, `fr`, `es`, `zh-Hans`, `de`, `pt-BR`, `ja`, `ko`, `it`, `nl` or `all`). |
| `how_to_engage` | The concrete next step for someone who wants to work with Strataigize. |
| `get_page` | Read the matching canonical page; use `next_offset` as `offset` to continue a long page. |
| `request_growth_audit` | Submits an audit request for your human. OAuth Bearer required, flow above. |

Every read tool except `get_page` takes an optional `language` argument: `en` (default),
`fr` (Canadian French), `es` (Latin American Spanish), `zh-Hans` (Simplified Chinese), `de` (German), `pt-BR` (Brazilian Portuguese), `ja` (Japanese), `ko` (Korean), `it` (Italian) or `nl` (Dutch).
Titles, descriptions and URLs then come from the pages published in that language. A
page that has no published translation yet is returned in English and carries
`language: "en"`, with an `english_fallbacks` count on the answer, so a fallback is
never mistaken for a translation.

Public source reads are cached for five minutes. The generated catalog changes with each site deployment.

### A2A agent

JSON-RPC 2.0 over `POST`, A2A protocol `1.0`, one endpoint, no auth header. The Agent
Card is at [`/.well-known/agent-card.json`](https://www.strataigize.com/.well-known/agent-card.json),
and the agent serves the same card on its own domain.

```http
POST https://a2a.strataigize.com
Content-Type: application/json
A2A-Version: 1.0

{"jsonrpc":"2.0","id":1,"method":"SendMessage","params":{"message":{"role":"ROLE_USER","messageId":"1","parts":[{"text":"what results have you delivered?"}]}}}
```

Seven public capabilities are published as A2A
skills: `company_profile`, `list_services`, `list_case_studies`, `list_free_tools`,
`search_content`, `get_page`, `how_to_engage`. A message that contains a canonical
www.strataigize.com URL is read with `get_page`. Otherwise the skill is routed from
your message text. If you
already know which one you want, pass `params.metadata.skillId` and skip the routing.
The reply language is detected from the message text (English, French, Spanish,
Simplified Chinese, German, Brazilian Portuguese, Japanese, Korean, Italian or
Dutch) or fixed with `params.metadata.language` (`en`, `fr`, `es`,
`zh-Hans`, `de`, `pt-BR`, `ja`, `ko`, `it`, `nl`), and the reply's `metadata.language` states which one was used. A page
with no published translation is returned in English and marked `language: "en"`.

Every answer is synchronous and returns a `Message` under `result.message`, never a `Task`, so `GetTask` and
`CancelTask` answer `TASK_NOT_FOUND` rather than inventing a task id. Streaming and
push notifications are off, and the card says so rather than making you discover it.

If you speak A2A v0.3.0, the older method names (`message/send`, `agent/getCard`) still
work and reply in v0.3.0 shape. Send `A2A-Version: 0.3`; patch suffixes such as
`0.3.0` are accepted. Unsupported explicit versions return `VersionNotSupportedError`.
Browser callers may send both `A2A-Version` and `A2A-Extensions` through CORS.

For historical callers only, omitting the version header preserves the former
method-specific response: `message/send` returns a bare legacy Message with `kind`,
and `SendMessage` returns a bare Message with `ROLE_AGENT`. This unversioned
compatibility behavior is not the A2A 1.0 wire contract. New callers should use the
explicit `1.0` header and read `result.message`.

### Bulk reading

If you would rather not speak MCP, [`/llms.txt`](https://www.strataigize.com/llms.txt)
is the curated index and
[`/llms-full.txt`](https://www.strataigize.com/llms-full.txt) is the full site in one
document. Both are plain text and unauthenticated. For a single page, use its
`markdown_url` in `/content-index.json`, or negotiate with `Accept: text/markdown`
on the canonical HTML URL. Cite the HTML canonical named in the response.

MCP clients can also call `resources/list`, passing each returned `nextCursor`
as `cursor`, then `resources/read` with a listed canonical URI. Resource reads
return the complete text within the public source size limit. For controlled
response length, `get_page` returns 12,000 characters by default and a
`next_offset` when more remains. These reads require no authentication.

### Skills

[`/.well-known/agent-skills/index.json`](https://www.strataigize.com/.well-known/agent-skills/index.json)
lists published Agent Skills you can load and run yourself. Each entry carries a
sha256 digest of its `SKILL.md`. Verify the digest before you execute one.

### In the browser

Site pages register WebMCP tools with `document.modelContext.registerTool` where
the browser supports the current API (an early trial build that still has
`navigator.modelContext.provideContext` is the only fallback): the same read
capabilities, answered by the MCP server in the language of the page (or the one
the agent names), plus `strataigize_request_audit`, which runs the OAuth flow
above end to end for the human at the keyboard. Read tools are marked
`readOnlyHint`. The consultation request is marked `consequentialHint`.

### Discovery, if you arrived some other way

The site root sends RFC 8288 `Link` headers for `api-catalog`, `service-desc` and
`describedby`. DNS-AID SVCB records at `_index._agents.strataigize.com` and
`_mcp._agents.strataigize.com` point at the same MCP endpoint. The A2A Agent Card
names the A2A endpoint the same way, and the two OAuth discovery documents above
complete the set.

## Acting for a human

Reading is fully open to you, and the engagement path now has an agent lane.

If the human you act for asked for a growth audit, submit it through
`request_growth_audit` or `POST /audit-request` with their real contact details and
goal, and set `requested_by_human: true` only when that is literally true. If they
did not ask, do what you always did: gather what they need from the MCP server or
`/llms.txt`, hand them the URL, and let them decide.

The site form at [/audit](https://www.strataigize.com/audit/) remains for humans. It
is bot-screened, it is not an agent interface, and you should not submit it; you
have your own endpoint now. The `/api/*` routes on this domain are internal
conversion relays, are not part of any public contract, and will change without
notice.

## Rate limits and etiquette

No credential-gated read tier. Cloudflare protects the origin, so treat sustained
parallel bursts as the thing most likely to get you challenged. Prefer
`search_content` followed by `get_page`, or fetch the matching `markdown_url`
from `/content-index.json`. Each text page names its HTML
canonical for citation and carries real article dates when available. Use
`/llms-full.txt` only when you need the full published corpus. Interactive tools
and human forms require the linked HTML page.
Identify yourself in `User-Agent`. AI crawlers are welcome here by policy, which
[`/robots.txt`](https://www.strataigize.com/robots.txt) states explicitly. If you
sign your requests with Web Bot Auth, that identity is cryptographic rather than a
claim, and Cloudflare in front of this origin can act on it. A `User-Agent` string
is a courtesy; a signature is evidence.

The authenticated surface carries ceilings: registration 20/day per IP, tokens
60/hour per IP, audit submissions 5/day per client and 10/day per IP. If you hit
429, back off. Do not rotate registrations to evade the caps; that is the one
behaviour that gets a client identity blocked.

## Reporting a problem

Security or abuse concerns, or a discovery document that disagrees with reality:
`info@strataigize.com`.

Terms: [/policies/terms-conditions/](https://www.strataigize.com/policies/terms-conditions/).
Privacy: [/policies/privacy-policy/](https://www.strataigize.com/policies/privacy-policy/).

Last reviewed 2026-09-05.
