> ## Documentation Index
> Fetch the complete documentation index at: https://tfh-docs-audit-mcp-content-fixes.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Developer Portal MCP

> Manage World developer portal apps from your AI coding assistant.

The Developer Portal MCP lets AI assistants create apps, configure World ID, manage Mini App metadata, upload app store assets, and submit apps for review.

It authenticates with a developer portal team API key. Treat that key like a secret: anyone with access to it can make changes to apps in that team.

## Endpoint

```text theme={"system"}
https://developer.world.org/api/mcp
```

## Create an API key

1. Open the [Developer Portal](https://developer.world.org).
2. Select your team.
3. Go to **API keys**.
4. Create or reset an API key.
5. Copy the generated key immediately. It is shown once.

Developer portal API keys start with `api_`.

## Authentication errors

Every method, including `initialize`, requires the API key. Authentication failures return HTTP 200 with JSON-RPC error code `-32001`, not an HTTP 401. The message distinguishes missing or malformed credentials from a key that was parsed but rejected:

```json theme={"system"}
{"jsonrpc": "2.0", "id": 1, "error": {"code": -32001, "message": "API key is required."}}
```

For a parsed but rejected key, the message is `API key is not valid.` Check that the client sends `Authorization: Bearer <API_KEY>` and copies the complete key from secure storage. Keys are shown only once; if yours is lost, generate a new key and update every client using the old one. The endpoint only accepts `POST`; `GET` returns HTTP 405 with `allow: POST, OPTIONS`.

## Connect your client

Replace `api_...` with the API key you copied from the Developer Portal. Codex and Cursor read the key from the `WORLD_DEVELOPER_API_KEY` environment variable at startup, so set it persistently (for example, in your shell profile, loaded from a secrets manager) rather than with a one-off `export`. VS Code prompts for the key once and stores it securely.

<Tabs>
  <Tab title="Claude Code">
    ```bash theme={"system"}
    claude mcp add world-developer-portal \
      https://developer.world.org/api/mcp \
      --transport http \
      --scope local \
      --header "Authorization: Bearer api_..."
    ```
  </Tab>

  <Tab title="Codex">
    ```bash theme={"system"}
    codex mcp add world-developer-portal \
      --url https://developer.world.org/api/mcp \
      --bearer-token-env-var WORLD_DEVELOPER_API_KEY
    ```
  </Tab>

  <Tab title="Cursor">
    Add this to `.cursor/mcp.json`:

    ```json theme={"system"}
    {
      "mcpServers": {
        "world-developer-portal": {
          "url": "https://developer.world.org/api/mcp",
          "headers": {
            "Authorization": "Bearer ${env:WORLD_DEVELOPER_API_KEY}"
          }
        }
      }
    }
    ```
  </Tab>

  <Tab title="VS Code">
    Add this to `.vscode/mcp.json`:

    ```json theme={"system"}
    {
      "inputs": [
        {
          "type": "promptString",
          "id": "world-developer-api-key",
          "description": "World Developer Portal API key",
          "password": true
        }
      ],
      "servers": {
        "world-developer-portal": {
          "type": "http",
          "url": "https://developer.world.org/api/mcp",
          "headers": {
            "Authorization": "Bearer ${input:world-developer-api-key}"
          }
        }
      }
    }
    ```
  </Tab>
</Tabs>

## Available tools

| Tool                               | Purpose                                                                               |
| ---------------------------------- | ------------------------------------------------------------------------------------- |
| `get_team_context`                 | List your team's apps and status.                                                     |
| `get_app_config`                   | Fetch app, World ID, Mini App, and app store configuration.                           |
| `create_app`                       | Create an external World ID app or Mini App.                                          |
| `configure_world_id`               | Create a managed World ID 4.0 relying party for an app.                               |
| `get_world_id_signing_key`         | Fetch the current signer address. Private keys are not returned.                      |
| `rotate_world_id_signing_key`      | Generate or set a new World ID signing key. The private key is returned once.         |
| `get_world_id_registration_status` | Fetch and sync World ID registration status from the registry contracts.              |
| `create_world_id_action`           | Create or update a World ID action for an app.                                        |
| `configure_mini_app`               | Update Mini App portal settings, app store metadata, and permissions.                 |
| `upload_app_image`                 | Upload logo, hero, content card, meta tag, or showcase images and patch app metadata. |
| `submit_app_for_review`            | Submit an app for review after explicit confirmation.                                 |

## Recommended flow

Start every session by asking the assistant to inspect the team:

```text theme={"system"}
Use the Developer Portal MCP to get my team context. If there is no app for this project, create one.
```

For an external World ID app:

```text theme={"system"}
Create a production external World ID app named Example, configure World ID, create an action called verify-account, and tell me which environment variables to add.
```

For a Mini App:

```text theme={"system"}
Create a Mini App named Example, fill the non-image app store metadata, upload the logo, content card, and showcase images I provide, and submit it for review after confirming the final values with me.
```

## Images

Use `upload_app_image` for app store images. It uploads the image and stores the correct filename in the matching metadata field.

The tool accepts either:

* `source_url`: a public HTTPS URL to a PNG or JPEG.
* `image_base64`: base64-encoded PNG or JPEG bytes for local files.

Use `configure_mini_app` for Mini App text, links, categories, permissions, countries, and languages. Use `upload_app_image` for logo, content card, meta tag, hero, and showcase assets.

Review submission still requires image metadata. Upload the required images before calling `submit_app_for_review`:

```text theme={"system"}
upload_app_image { app_id, image_type: "logo", image_base64 | source_url }
upload_app_image { app_id, image_type: "content_card", image_base64 | source_url }
upload_app_image { app_id, image_type: "showcase_1", image_base64 | source_url }
```

## Timeouts and retries

A timeout or dropped connection doesn't tell you whether a call went through, and these tools don't replay the original result. Re-read state (`get_world_id_signing_key`, `get_world_id_registration_status`, `get_app_config`) before you retry:

* `configure_world_id` and `rotate_world_id_signing_key`: the private key is only in the original response. If that response is lost, the key is unrecoverable, but the portal still applies its signer address. Retrying `configure_world_id` returns the existing registration with `signing_key: null`. Retrying `rotate_world_id_signing_key` fails with `-32004` (`rotation_in_progress`) until the registration status is `registered` again. If `get_world_id_signing_key` shows a signer address you don't hold, wait until `get_world_id_registration_status` reports `registered`, then rotate again from a trusted channel (see [Security notes](#security-notes)).
* `submit_app_for_review`: if the first call went through, a retry fails with `-32004` `Only unverified apps can be submitted.` Check `get_app_config` for the review status instead.

## Security notes

* Store generated World ID private keys immediately. They are returned once and are not recoverable from the portal.
* `configure_world_id` and `rotate_world_id_signing_key` return the private key as a tool call result, not a one-time dialog — it passes through the assistant's model context and, depending on the client, may be persisted in session transcripts or debug logs. Treat it as sensitive. If it was generated through a client whose logs aren't under your team's control, don't just rotate again from that same client — the replacement key would leak through the identical path. Rotate from the Developer Portal dashboard instead: it generates the new key in your browser and sends only the signer address.
* Keep API keys out of files you commit. Claude Code's `--scope project` writes the header to `.mcp.json`, which is meant to be committed; the examples above use local scope, an environment variable, or an input prompt instead.
* Use a separate API key per local agent or project when possible.
* Delete or rotate API keys that are no longer needed.
* Confirm destructive actions before asking the assistant to rotate a signer key or submit an app for review.
