Skip to main content

OpenAI MCP Extensions for Python

The Python SDK provides server-side OpenAI extensions for the official MCP Python SDK. Use @openai/mcp-extensions/app for MCP App extensions.

Installation

Install the Python extension SDK from PyPI.

uv add openai-mcp-extensions

Server Setup

Initialize the MCP Apps and OpenAI extensions for use with an MCP Server.

from mcp.server.apps import Apps
from mcp.server.mcpserver import MCPServer

from openai_mcp_extensions import OpenAIExtensions

apps = Apps()
openai_extensions = OpenAIExtensions()

Register extension handlers and resources before constructing MCPServer.

The following examples are separate configurations. Include each extension your server uses in its extensions list.

Structured Settings

from typing import Any, Literal

from mcp.server.mcpserver import MCPServer
from mcp.server.mcpserver.context import Context
from pydantic import BaseModel, Field

from openai_mcp_extensions import (
    OpenAISettings,
    OpenAISettingsGroup,
    OpenAISettingsProperty,
)
from preferences import load_preferences, update_preferences


class Preferences(BaseModel):
    units: Literal["mm", "in"] = Field(title="Measurement units")
    show_grid: bool = Field(alias="showGrid", title="Show grid")


settings = OpenAISettings(
    schema=Preferences,
    # Optionally arrange fields into groups.
    # Omitted properties appear in an "Other settings" group below the listed groups.
    layout=[
        OpenAISettingsGroup(
            title="Display",
            items=[OpenAISettingsProperty(property="units"), OpenAISettingsProperty(property="showGrid")],
        ),
    ],
)


# Synchronous handlers run in a worker thread. Async handlers run on the event loop.
@settings.read
async def read_settings(context: Context[Any, Any]) -> Preferences:
    return await load_preferences(context)


# Synchronous handlers run in a worker thread. Async handlers run on the event loop.
@settings.update
async def update_settings(set: dict[str, Any], context: Context[Any, Any]) -> Preferences:
    return await update_preferences(set, context)


server = MCPServer(
    "viewer",
    extensions=[settings],
    # Only needed if your server does not support the 2026-07-28 spec and/or supports
    # the legacy initialize handshake.
    # https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#initialization
    middleware=[settings.advertise_legacy_capability],
)

UI Entrypoints

from mcp.server.apps import APP_MIME_TYPE
from mcp.server.mcpserver.resources import TextResource
from mcp_types import Icon

from openai_mcp_extensions import (
    OpenAIFileEntrypoint,
    OpenAIGlobalEntrypoint,
    OpenAISettingsEntrypoint,
    OpenAIThreadEntrypoint,
    OpenAIUiQuickAction,
    OpenAIUiQuickActionToolTarget,
    OpenAIUiResourceMetadata,
    OpenAIUiToolMetadata,
)

apps.add_resource(
    TextResource(
        uri="ui://table/viewer",
        name="table",
        mime_type=APP_MIME_TYPE,
        text="<!doctype html><title>Table</title><main>Table viewer</main>",
        meta={
            "openai/ui": OpenAIUiResourceMetadata(
                preferred_display_mode="fullscreen",
                available_display_modes=["inline", "fullscreen"],
            ).model_dump(by_alias=True, exclude_none=True),
        },
    ),
)


@apps.tool(
    resource_uri="ui://table/viewer",
    meta={
        "openai/ui": OpenAIUiToolMetadata(
            entrypoints=[
                OpenAIGlobalEntrypoint(
                    quick_action=OpenAIUiQuickAction(
                        title="New table",
                        icons=[Icon(src="https://example.com/plus.svg")],
                        target=OpenAIUiQuickActionToolTarget(name="create_table", arguments={}),
                    ),
                ),
                OpenAIThreadEntrypoint(),
                OpenAIFileEntrypoint(extensions=[".csv", ".tsv"]),
            ],
        ).model_dump(by_alias=True, exclude_none=True),
    },
)
def open_table() -> str:
    return "Open the table viewer."


server = MCPServer("my-server", extensions=[apps, openai_extensions])

Filesystem Access

from typing import Any

from mcp.server.mcpserver.context import Context

from openai_mcp_extensions import get_resource_path


def opened_file_path(context: Context[Any, Any]) -> str | None:
    return get_resource_path(context.request_context.meta)

Composer Mentions

from typing import Any

from mcp.server.mcpserver import MCPServer
from mcp.server.mcpserver.context import Context
from mcp_types import ResourceLink

from openai_mcp_extensions import (
    OpenAIExtensions,
    OpenAIMentionSearchParams,
    OpenAIMentionSearchResult,
)

openai_extensions = OpenAIExtensions()


@openai_extensions.mentions.search
async def search_mentions(
    params: OpenAIMentionSearchParams,
    context: Context[Any, Any],
) -> OpenAIMentionSearchResult:
    return OpenAIMentionSearchResult(
        items=[
            ResourceLink(
                uri=f"mcp://issues/{params.query}",
                name=params.query,
            ),
        ],
    )


server = MCPServer("issue-tracker", extensions=[openai_extensions])

Form Elicitation

NOTE: OpenAI-registered MCP servers require MRTR for form elicitation. Direct MCP connections still support legacy forms through elicit_input, which does not implement MRTR.

Suggested Values

Users can enter values that are not listed. The same field constraints apply to suggested and entered values.

from typing import Annotated

from pydantic import BaseModel, Field


class ReviewForm(BaseModel):
    purpose: str = Field(
        min_length=1,
        json_schema_extra={
            "x-openai-suggestions": [{"const": "prototype", "title": "Prototype"}],
        },
    )
    checks: list[
        Annotated[
            str,
            Field(
                min_length=1,
                json_schema_extra={
                    "x-openai-suggestions": [{"const": "clearance", "title": "Clearance"}],
                },
            ),
        ]
    ]

Resource Selection

from typing import Any

from mcp.server.elicitation import ElicitationResult
from mcp.server.mcpserver import MCPServer
from mcp.server.mcpserver.context import Context
from mcp_types import Resource
from pydantic import BaseModel, Field, FileUrl

from openai_mcp_extensions import OpenAIExtensions
from openai_mcp_extensions.form import UserResourceOptions, resource_input

openai_extensions = OpenAIExtensions()
server = MCPServer("presentations", extensions=[openai_extensions])


class PresentationForm(BaseModel):
    images: list[FileUrl] = Field(
        default_factory=list,
        max_length=5,
        json_schema_extra={
            **resource_input(
                options=[
                    Resource(
                        uri="file:///images/sales.png",
                        name="sales.png",
                        title="Sales image",
                        meta={
                            "openai/thumbnail": {"src": "https://example.com/sales.png"},
                            "openai/preview": {
                                "target": {
                                    "type": "resource_link",
                                    "uri": "file:///images/sales.png",
                                    "name": "sales.png",
                                    "mimeType": "image/png",
                                },
                            },
                        },
                    ),
                ],
                user_options=UserResourceOptions(accept=["image/*"]),
            ),
            "default": ["file:///images/sales.png"],
        },
    )


@server.tool()
async def choose_images(context: Context[Any, Any]) -> ElicitationResult[PresentationForm]:
    return await openai_extensions.elicit_input(
        context,
        mode="form",
        message="Choose reference images",
        schema=PresentationForm,
    )

Release files for openai-mcp-extensions 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for openai-mcp-extensions 0.1.0
File Size Uploaded
openai_mcp_extensions-0.1.0.tar.gz 22.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for openai-mcp-extensions 0.1.0
File Interpreter ABI Platform
openai_mcp_extensions-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 47.6 kB

Release files / openai_mcp_extensions-0.1.0.tar.gz

Download URL openai_mcp_extensions-0.1.0.tar.gz
Size 22.6 kB
Tags Source
SHA-256 checksum
How to use checksums
fc7e0f7805719ef40dd3654a2a9f876ece313d61b4268f0841cea27ba05afe00
BLAKE2b-256 checksum
How to use checksums
1a3124c376a66f1fd6f3093929b4bec7f0a0b87e688f04dcb2382dacecb64cbf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.

Transparency log

Release files / openai_mcp_extensions-0.1.0-py3-none-any.whl

Download URL openai_mcp_extensions-0.1.0-py3-none-any.whl
Size 25.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6694e102c746dd4f9c0a6c0f668dd11ad627d676153bf5d02e9f152c9a913e4c
BLAKE2b-256 checksum
How to use checksums
15b50be87c1355db5587d92b8c3979a14baaa02ae8a518a1b7c6d956a15caf69
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page