Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions doctrine/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,37 @@ evidence (Run Records / Retro Notes) behind it. Required by constitution
invariant I8; written by `/tune-pipeline` when a human approves a
proposal, or by hand for direct human edits.

## 2026-09-30 — move credential setup to the Identity section

Files: `doctrine/speakeasy-setup.md`, `guides/*/{speakeasy,external,research}.md`,
`guides/*/meta.yaml`.

Evidence: an audit of every guide against `speakeasy-api/gram` main
`68b3f78ffec0ab6072ece4b7cc2ee3868c6a7c06` found that #6364, #6905, #6906,
#6813 and #6974 replaced the remote-server **Authentication** section and
**Attach Remote Identity Provider** sheet with an **Identity** section. The
human asked for this correction as a pull request.

- Choose **User Identity**, **Service Account**, or **No Identity** when
adding the server (catalog dialog and **Hosted remotely**), and in
**Settings > Identity** afterwards.
- Replace the provider form with the provider picker; route providers
without discoverable metadata through **Create a custom identity
provider**.
- Replace **Session Client** / **Client Type** with **Existing client**,
**Auto-Configure** (CIMD or DCR), and **Manual**; record when Manual must
be chosen over the Auto-Configure default.
- Scopes go under **Advanced > Scope**, space-separated; a blank value
requests every PRM scope. The auth method and audience controls are gone.
- API keys and tokens go in the **Service Account** credential, not
**Upstream Headers**. Servers left **Disabled** are enabled from
**Server Availability**.
- Refresh every guide and apply the audit's verified provider fixes.

Verification is source-level plus live provider probes and repository
validation; this entry does not claim a production-browser walkthrough.
I8: human-approved correction.

## 2026-09-17 — align in-app setup steps with current Control Plane UI

Files: `doctrine/speakeasy-setup.md`, `guides/*/speakeasy.md`,
Expand Down
244 changes: 151 additions & 93 deletions doctrine/speakeasy-setup.md

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions guides/asana/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ remotes:
locator: https://developers.asana.com/docs/integrating-with-asanas-mcp-server
name: Integrating with Asana's MCP Server
classification: official
observed_at: "2026-08-06T23:24:28Z"
observed_at: "2026-09-30T21:30:00Z"
- source: provider-documentation
locator: https://developers.asana.com/docs/using-asanas-mcp-server
name: Using Asana's MCP Server
Expand All @@ -50,11 +50,11 @@ remotes:
- source: endpoint-observation
locator: https://mcp.asana.com/v2/mcp
classification: official
observed_at: "2026-08-06T23:24:28Z"
observed_at: "2026-09-30T21:30:00Z"
- source: endpoint-observation
locator: https://mcp.asana.com/.well-known/oauth-protected-resource/v2
classification: official
observed_at: "2026-08-06T23:24:28Z"
observed_at: "2026-09-30T21:30:00Z"
provenance:
- source: pulsemcp
locator: com.pulsemcp.mirror/asana-mcp
Expand All @@ -66,7 +66,7 @@ provenance:
locator: https://developers.asana.com/docs/integrating-with-asanas-mcp-server
name: Integrating with Asana's MCP Server
classification: official
observed_at: "2026-08-06T23:24:28Z"
observed_at: "2026-09-30T21:30:00Z"
- source: provider-documentation
locator: https://developers.asana.com/docs/using-asanas-mcp-server
name: Using Asana's MCP Server
Expand Down Expand Up @@ -115,17 +115,17 @@ provenance:
- source: endpoint-observation
locator: https://mcp.asana.com/v2/mcp
classification: official
observed_at: "2026-08-06T23:24:28Z"
observed_at: "2026-09-30T21:30:00Z"
- source: endpoint-observation
locator: https://mcp.asana.com/.well-known/oauth-protected-resource/v2
classification: official
observed_at: "2026-08-06T23:24:28Z"
observed_at: "2026-09-30T21:30:00Z"
- source: endpoint-observation
locator: https://app.asana.com/.well-known/oauth-authorization-server
classification: official
observed_at: "2026-08-06T23:24:28Z"
observed_at: "2026-09-30T21:30:00Z"
- source: repository-doctrine
locator: doctrine/speakeasy-setup.md
name: Speakeasy setup canonical section
classification: official
observed_at: "2026-08-06T23:24:28Z"
observed_at: "2026-09-30T21:30:00Z"
106 changes: 64 additions & 42 deletions guides/asana/research.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ server is outside this guide.
authorization-code and refresh-token grants, `client_secret_post` and
`client_secret_basic`, and PKCE method `S256`; it has no dynamic
registration endpoint.
- **Scope:** do not configure a scope. The integration guide says MCP
apps do not require specific scopes: use `default` or omit `scope`.
- **Scope:** only `default`. The integration guide says MCP apps do not
require specific scopes: use `default` or omit `scope`.
Its Common issues section more narrowly says an explicit `scope`
parameter can produce **Invalid scope(s) requested** and should be
removed. The live resource metadata advertises `default`.
Expand Down Expand Up @@ -80,7 +80,7 @@ Values the Speakeasy AI Control Plane needs:
Paste `{{ gram.oauth.callback_url }}` into the app's **Redirect URL**
setting on the **OAuth** page ({#configure-oauth-redirect}). Asana requires
the redirect URL in the app settings to match the URL in the authorization
request exactly. No provider scope value is needed.
request exactly. The only scope value is `default`.

Before users connect, set the app's **Distribution method**. For an
internal deployment, **Specific workspaces** limits authorization to the
Expand Down Expand Up @@ -176,51 +176,68 @@ The documented path is Asana main app > profile photo > **Settings** >

## Speakeasy setup

Canonical source: `doctrine/speakeasy-setup.md`, observed
`2026-08-06T23:24:28Z`.
Canonical source: `doctrine/speakeasy-setup.md` (gram main `68b3f78`),
observed `2026-09-30T21:30:00Z`.

Per-guide values:

- Remote URL: `https://mcp.asana.com/v2/mcp`
- Transport: `streamable-http` (the add form's **Transport** field is
read-only)
- Authentication Option: OAuth with a manually pre-registered client;
Asana publishes discoverable OAuth metadata
- **Client ID** and **Client secret**: produced in
{#create-mcp-app}
- Redirect URI registered with Asana: `{{ gram.oauth.callback_url }}` in
{#configure-oauth-redirect}
- Provider scopes: none to enter; Asana says omit `scope` for MCP apps
- Further reading:
`https://developers.asana.com/docs/using-asanas-mcp-server`
- Remote URL: `https://mcp.asana.com/v2/mcp` (shared, not tenanted)
- Add-server path: catalog only (**From the catalog**), resolved by the
Speakeasy MCP Catalog record `com.pulsemcp.mirror/asana-mcp`.
- Authentication Option: `oauth-mcp-app`, mapped to **User Identity**.
**Client ID** and **Client secret** come from {#create-mcp-app}; the
redirect `{{ gram.oauth.callback_url }}` is registered at
{#configure-oauth-redirect}.
- Probe outcome (2026-09-30): an unauthenticated JSON-RPC `initialize` POST
returned 401 with `resource_metadata=
"https://mcp.asana.com/.well-known/oauth-protected-resource/v2"`.
- PRM issuer: `https://app.asana.com`. PRM `scopes_supported`: `default`.
- Issuer metadata: `https://app.asana.com/.well-known/oauth-authorization-server`
(issuer matches the PRM byte for byte) advertises no
`registration_endpoint` and no `client_id_metadata_document_supported`.
Neither CIMD nor DCR is available.
- Registration choice: **Manual**. The dashboard defaults to **Manual** here
because nothing automatic is advertised. Creation with **User Identity**
cannot register a client, so the server is kept **Disabled** and the
result points to **Settings > Identity**; the guide says this is expected
and ends with **Server Availability**.
- Scope string for **Advanced > Scope**: `default`. Asana's integration
guide says to use `default` or omit `scope`; its Common issues section
says other scope values produce "Invalid scope(s) requested". A blank
**Scope** would request the PRM list, which is also only `default`.
- Further reading: `https://developers.asana.com/docs/using-asanas-mcp-server`

### Add the server in Speakeasy {#add-server-in-speakeasy}

In the Speakeasy AI Control Plane sidebar, under **Connect**, select
**Sources**, then click **Add Source**.
In the Speakeasy AI Control Plane sidebar, under **MCP Gateway**, select
**MCP**, then click **Add new** to open **Add MCP server**. Choose **From
the catalog**. On the **MCP Catalog** page, find **Asana** using **Search
MCP servers...**, open its catalog entry, and click **Add**. In **Add to
Project**, select **User Identity** under **Identity** (the dialog
preselects **No Identity** unless the entry supports client registration),
then click **Add to Project**. Finish or **Skip for now** any
**Guardrails** step. Because Asana needs a hand-registered client, the
result says to finish setup in **Settings > Identity** and the server stays
**Disabled**.

Choose **3rd-party server**. On the **MCP Catalog** page, find **Asana**
using **Search MCP servers...**, open it with **View**, and click **Add**.
In the **Add to Project** dialog, click **Add to Project**. This creates
the hosted MCP server and opens its **Overview** page.

Screenshot note: capture the **Add Source** menu on **Sources**, or
Asana's catalog entry.
Screenshot note: Asana's catalog entry in **Add to Project** with **User
Identity** selected.

### Connect your credentials {#connect-speakeasy-credentials}

From the server's **Overview**, open **Settings**. Under
**Authentication**, use **Use Discovered** when the published Asana
metadata is offered; otherwise click **Configure Manually**. In
**Attach Remote Identity Provider**, set **Client Type** to **Manual**.
The sheet shows **Redirect URI** with a copy button. Its value must match the
`{{ gram.oauth.callback_url }}` value entered in Asana at
{#configure-oauth-redirect}. Paste the **Client ID** and **Client
Secret (optional)** copied at {#create-mcp-app}, then click **Attach
Identity Provider**.

Screenshot note: capture **Attach Remote Identity Provider** with the
Redirect URI and credential fields visible and all credential values
In the server's **Settings**, open the **Identity** section and select
**User Identity**. In **Choose an identity provider**, confirm
`https://app.asana.com` (badged **Will be created** when new), or choose it
with **Search identity providers…**. Choose **Manual**, paste the **Client
ID** and **Client secret** from {#create-mcp-app} (Asana requires the
secret despite the "Optional" placeholder), enter `default` under
**Advanced > Scope**, and click **Save**. This surface shows no redirect
URI; {#configure-oauth-redirect} carries the callback check. Then open
**Danger Zone > Server Availability** and turn on **Enable MCP server** so
it shows **Enabled**.

Screenshot note: **Settings > Identity** with **User Identity**, the
`app.asana.com` provider, and **Manual** selected; credential values
redacted.

Closing pointer: "This guide covers setup only. For anything beyond it —
Expand All @@ -235,7 +252,7 @@ https://developers.asana.com/docs/using-asanas-mcp-server."
workspaces**.
- The integration page documents protected-resource metadata at
`https://mcp.asana.com/v2/.well-known/oauth-protected-resource`, which
returned 404 this run. The live MCP challenge points to
returned 404 this run and again on 2026-09-30. The live MCP challenge points to
`https://mcp.asana.com/.well-known/oauth-protected-resource/v2`, which
returned valid metadata naming the exact MCP resource. This discrepancy
does not change the browser setup path and should be rechecked during
Expand Down Expand Up @@ -327,6 +344,11 @@ Sources drawn from:
`com.pulsemcp.mirror/asana-mcp` (title **Asana**) — observed
`2026-08-06T23:24:28Z`, `source: pulsemcp`. Backs catalog presence and
the catalog-only add-server path.
- `doctrine/speakeasy-setup.md` — observed `2026-08-06T23:24:28Z`. Backs the
transcluded Speakeasy-side flow, fixed anchors, exact product labels,
callback-template behavior, and closing-pointer form.
- `doctrine/speakeasy-setup.md` — observed `2026-09-30T21:30:00Z` (gram
main `68b3f78`). Backs the transcluded Speakeasy-side flow, fixed
anchors, exact product labels, callback-template behavior, and
closing-pointer form.
- Live re-probe on `2026-09-30T21:30:00Z` of `https://mcp.asana.com/v2/mcp`,
its PRM, and `https://app.asana.com/.well-known/oauth-authorization-server`
confirmed the 401 challenge, issuer, `default` scope, and absence of
registration and CIMD support recorded above.
64 changes: 20 additions & 44 deletions guides/asana/speakeasy.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,62 +3,38 @@
### Add the server in Speakeasy {#add-server-in-speakeasy}

1. In the Speakeasy AI Control Plane sidebar, under **MCP Gateway**, select **MCP**.
2. Select **Add new** to open the **Add MCP server** page.
2. Click **Add new** to open **Add MCP server**.
3. Choose **From the catalog**.
4. On the **MCP Catalog** page, find **Asana** using **Search MCP servers...**.
5. Open the **Asana** entry.
6. Select **Add**.
7. In **Add to Project**, select **Add to Project**.
5. Open the **Asana** entry and click **Add**.
6. In the **Add to Project** dialog, under **Identity**, select **User Identity**. The dialog may preselect **No Identity**.
7. Click **Add to Project**. If the dialog offers a **Guardrails** step, finish it or click **Skip for now**.

After installation, select **Configure MCP settings** on the completion screen to open the server, then open **Settings**.
Asana needs a client registered by hand, so the result says to finish setup in **Settings > Identity**, and the server stays **Disabled** for now. This is expected. Click **Finish setup** on the server's result to open its **Settings**.

<!-- screenshot: the Add MCP server page, or Asana's catalog entry -->
<!-- screenshot: Asana's catalog entry in Add to Project with User Identity selected -->

### Connect your credentials {#connect-speakeasy-credentials}

Select **Configure MCP settings** on the completion screen, then open the server’s **Settings**.
In the server's **Settings**, find the **Identity** section.

Under **Authentication**, if unconfigured, select **Use Discovered** when available; otherwise select **Configure Manually**. If configured but no provider is attached, use **Connected services > Add provider**. If the intended provider is already attached, use its existing controls and skip the provider/client creation and attachment steps below; do not add a duplicate.
1. Select **User Identity**.
2. In **Choose an identity provider**, confirm the provider is `https://app.asana.com`. It may be badged **Will be created**. If no provider or a different one is selected, open the picker, search for `app.asana.com` in **Search identity providers…**, and choose it.
3. Under the provider, choose **Manual**.
4. Paste the **Client ID** from [Create the MCP app](external.md#create-mcp-app) into **Client ID**.
5. Paste the **Client secret** from [Create the MCP app](external.md#create-mcp-app) into **Client secret**. Asana requires it, even though the field shows "Optional".
6. Open **Advanced** and enter `default` in **Scope**. Do not add other scopes; Asana rejects them with "Invalid scope(s) requested".
7. Click **Save**.

#### Select the identity provider
This section does not show the redirect URI. Asana accepts the connection only if [Configure the OAuth redirect](external.md#configure-oauth-redirect) registered `{{ gram.oauth.callback_url }}`.

In **Attach Remote Identity Provider**, **Identity Provider** defaults to **Select existing** when project issuers are available. Select the matching provider and skip the new-provider fields below. Otherwise choose **Add new** (or use the new-provider form shown when none exist).
Then turn the server on:

For a new provider only, confirm **Issuer URL**, the auto-derived **Slug**, and **Endpoints**. Discovery runs automatically for a seeded issuer; after typing or changing the URL, select **Discover** only if offered.
1. In **Settings**, open **Danger Zone**.
2. Under **Server Availability**, turn on **Enable MCP server** so it shows **Enabled**.

For a new provider, enter **Issuer URL** `https://app.asana.com` and keep the auto-derived **Slug**. If discovery does not populate **Endpoints**, enter:
Each user sees Asana's authorization prompt the first time they use the server.

Authorization endpoint:

```text
https://app.asana.com/-/oauth_authorize
```

Token endpoint:

```text
https://app.asana.com/-/oauth_token
```

<!-- source: https://app.asana.com/.well-known/oauth-authorization-server; public metadata checked 2026-09-17 -->

#### Select the session client

Under **Session Client**, choose **Select existing** only for a client whose saved credentials, scopes, and audience match the requirements below; otherwise choose **Add new**. When reusing a matching client, skip directly to **Verify the callback and attach** below. Do not create credentials or register the client again. Otherwise choose **Add new** (or use the new-client form shown when no clients exist) and complete these new-client-only steps:

Do not enter a scope during this setup.

1. In **Attach Remote Identity Provider**, set **Client Type** to **Manual**.
1. Paste the **Client ID** saved in [Create the MCP app](external.md#create-mcp-app) into **Client ID**.
1. Paste the **Client secret** saved in [Create the MCP app](external.md#create-mcp-app) into **Client Secret (optional)**.

#### Verify the callback and attach

1. Confirm that the callback URL registered with the provider is `{{ gram.oauth.callback_url }}`. For a new manual client, also compare it with the sheet's displayed **Redirect URI**. The existing-client selection does not display that field; check the registered callback in the provider's app settings instead.
2. Click **Attach Identity Provider**.

For the provider-side callback setting, see [Configure the OAuth redirect](external.md#configure-oauth-redirect).

<!-- screenshot: Attach Remote Identity Provider with the Redirect URI and credential fields visible and all credential values redacted -->
<!-- screenshot: Settings > Identity with User Identity, the app.asana.com provider, and Manual selected; credential values redacted -->

This guide covers setup only. For anything beyond it — billing, tool behavior, limits — see [Asana's MCP documentation](https://developers.asana.com/docs/using-asanas-mcp-server).
4 changes: 2 additions & 2 deletions guides/atlassian/external.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ You need no Atlassian-side configuration unless your organization restricts OAut
5. Check whether the allowed domains cover this hosted OAuth callback:

```
https://app.getgram.ai/mcp/remote_login_callback
{{ gram.oauth.callback_url }}
```

6. If it is not covered, select **Add domain**.
7. Enter this exact custom domain pattern:

```
https://app.getgram.ai/mcp/remote_login_callback
{{ gram.oauth.callback_url }}
```

8. Use the submission control shown in the console.
Expand Down
Loading
Loading