apps Package

Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT License.

Classes

ActivityContext

Context object passed to activity handlers with middleware support.

Note

The single-connection OAuth surface here - <xref:is_signed_in>,

<xref:user_token>, user_graph, sign_in,

sign_out and get_user_token - predates

multi-connection support and is deprecated.

Register connections with

app.add_oauth_flow(name) and use the returned OAuthFlow, which

pins every operation to the connection that owns it.

ActivityEvent

Event emitted when an activity is processed.

ActivityResponseEvent

Event emitted by a plugin before an invoke response is returned.

ActivitySentEvent

Event emitted when an activity is sent.

Agent365Baggage

Opt-in Agent365 OpenTelemetry baggage bridge for Teams activity context.

Agent365BaggageKeys

Agent365-compatible OpenTelemetry baggage keys.

Agent365BaggageOptions

Host-wide options for Agent365 baggage derived from inbound activities.

Agent365ScopeOpener

Opens a proactive Agent365 baggage scope with bound host policy.

Agent365ScopeOptions

Host-wide defaults for proactive Agent365 baggage scopes.

App

The main Teams application orchestrator.

Manages plugins, tokens, and application lifecycle for Microsoft Teams apps.

AppOptions

Configuration options for the Teams App.

AppTelemetryOptions

Telemetry options applied across SDK-owned app flows.

AppTokenProvider

Public token source backed by the credentials configured on an App.

ClientContext

Runtime information about the client and session in Microsoft Teams.

CoreActivity

Core activity fields that all transports need to know about. Extensible for protocol-specific fields via extra="allow".

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

DependencyMetadata

Information associated with a plugin dependency

DownloadedFile

A buffered, point-in-time snapshot of a downloaded file's bytes that the caller owns.

Returned by IncomingFile.download(). The bytes are already in memory, so the convenience readers here are synchronous and never re-download. Because it is a snapshot, holding one and reusing it is the way to read the same file several ways without re-fetching through the live IncomingFile handle.

ErrorEvent

Event emitted when an error occurs.

EventMetadata

Information associated with the plugin event

EventProtocol

Protocol for event objects in the Teams app system.

FastAPIAdapter

Default HttpServerAdapter implementation wrapping FastAPI + uvicorn.

FileAccessError

Raised when the identity used was refused by the storage service.

Distinct from FileUrlExpiredError, which means a pre-authorized URL lapsed and no usable Graph route existed. This error means the Graph route was the one that failed, refused by the service after the request was made.

FileCredentialError

Raised when no credential was available for the Graph call. Detectable before any HTTP request.

Distinct from FileUrlExpiredError, which means a pre-authorized URL lapsed and no usable Graph route existed. This error means the Graph route was ruled out before the request, because no usable credential was available: either a token could not be acquired, or the one acquired carries no file-capable permission.

FileError

Base class for the diagnosable failures on the inbound-file path: an expired URL, an unsupported scope, and a refused Graph read.

Lets a caller catch those with one except clause, so a new one can be added without callers changing. A transport or service failure the SDK cannot attribute, such as a Graph 5xx, is not one of these and surfaces as a plain RuntimeError.

FileScopeNotSupportedError

Raised when file bytes are requested for a conversation scope whose download path is not implemented.

Only personal (1:1) uploaded files download directly. groupChat files are surfaced by list(), but fetching their bytes needs Graph; download()/stream() throws until that path lands.

FileUrlExpiredError

Raised when an inbound file's short-lived download URL has expired and can no longer fetch bytes.

A personal file's pre-authorized tempauth download URL is valid only briefly. A fetch after it lapses gets a 401/403 from the platform. A handler that downloads once (and does not keep the handle) should not hit this. reason distinguishes the two cases:

  • first_fetch: the first fetch came after the URL lapsed, so no bytes were retrieved. There is no recovery: the

    URL carried its own credential, and the SDK does not fall back to Graph with an app identity. The file has to be sent again.

  • reread: edge case. An earlier download succeeded, then a later re-fetch through the same handle lapsed. Avoid it by calling download() once and reusing the returned DownloadedFile rather than re-reading the handle.
FilesAccessor

Accessor for the uploaded files on the current inbound activity, exposed as ctx.files.

"Files" is the uploaded-file view over the raw ctx.activity.attachments array. Uploaded files arrive as attachments where content_type is file.download.info, carrying file metadata rather than the bytes themselves. The metadata names where the bytes live: a pre-authorized download_url when the platform issues one, otherwise a content_url that locates the item so Graph can resolve it. This accessor maps each to an IncomingFile, and skips everything else in attachments (adaptive cards, mentions, other non-file content) as well as malformed file entries, never throwing. For each file it returns, the original wire attachment (the metadata object, not the bytes) is retained on IncomingFile.raw. A malformed or non-file attachment is reachable only through the raw activity.attachments array.

This covers the file-upload path, not "any uploaded media". What matters is how the content arrived, not the file's MIME type, so file type is unrestricted (pdf, docx, png, etc.) as long as it was sent as an uploaded file. An image sent as a file appears here, but the same image pasted inline does not.

The optional client is the app's shared httpx.AsyncClient, threaded into every IncomingFile so downloads reuse one connection pool instead of building and tearing down a client per file. It is the raw client rather than the SDK's wrapper on purpose: a download URL embeds its own tempauth credential, so the request must not pick up the bot's Authorization header. When omitted, each download creates and closes its own client.

FunctionContext

Context provided to a remote function execution in a Teams app.

HtmlWidgetMarkdownOptions

Options for building an HTML widget markdown string.

HttpServer

Core Teams HTTP server. Not a plugin — owned directly by the App.

Manages an HttpServerAdapter instance and handles JWT validation and activity processing for the Teams protocol.

HttpServerAdapter

Protocol for framework-specific HTTP server adapters.

Implement this adapter to plug in any HTTP framework (FastAPI, Starlette, Flask, etc.). The SDK calls these methods with framework-agnostic HttpRequest/HttpResponse objects so the adapter can translate to/from the underlying framework.

HttpStream

HTTP-based streaming implementation for Microsoft Teams activities.

Flow:

  1. emit() adds activities to a queue
  2. _flush() drains the entire queue under a lock.
  3. Informative typing updates are sent immediately if no message started.
  4. Message text are combined into a typing chunk.
  5. Another flush is scheduled if more items remain.
  6. close() waits for queue to empty, then sends final message with stream_type='stream_final'

The timeout cancellation ensures only one flush operation is scheduled at a time. The delays between flushes is to ensure we dont hit API rate limits with Microsoft Teams.

Initialize a new HttpStream instance.

InboundActivityTokenValidator

Validator for inbound Teams activities.

Classic bot activities use Bot Framework connector tokens. Agent ID activities use Entra tokens whose audience is the Agent 365 app blueprint app ID.

IncomingFile

A lazy handle to a file attached to the current inbound activity.

Nothing is downloaded until a byte method is called. The handle stays live and holds no memoized bytes, so each of stream()/download()/text()/save_as() fetches afresh. For a personal file that re-fetch is bounded by the short-lived download URL lifetime and may hit its expiry; to read the same file several ways, call download() once and reuse the returned DownloadedFile.

InjectWidgetProtocolOptions

Options for injecting the MCP Apps protocol into widget HTML.

OAuthFlow

One named OAuth connection, plus the handlers attached to it.

Created via app.add_oauth_flow(...) — not constructed directly.

OAuthFlowRegistry

Case-insensitive, insertion-ordered collection of OAuthFlow.

Subclasses Mapping, so in, .get(), .values(), len() and truthiness all work without extra code.

PluginActivityEvent

Event emitted by a plugin when an activity is received.

Create new instance of PluginActivityEvent(token, activity, conversation_ref)

PluginActivityResponseEvent

Event emitted before an activity response is sent

Create new instance of PluginActivityResponseEvent(activity, conversation_ref, response)

PluginActivitySentEvent

Event emitted when an activity is sent.

Create new instance of PluginActivitySentEvent(activity, conversation_ref)

PluginBase

The base plugin for Teams app plugins.

PluginErrorEvent

Event emitted when an error occurs.

Create new instance of PluginErrorEvent(error, activity)

PluginOptions

Plugin metadata

PluginStartEvent

Event emitted when the plugin is started.

Create new instance of PluginStartEvent(port,)

SecurityPolicyWarning

A warning produced by validate_security_policy when the widget HTML references an external origin not present in the declared security policy.

Diagnostic: ExperimentalTeamsHtmlWidget

SignInEvent
SignInFailureEvent
StartEvent

Event emitted when the app starts.

StateOptions

Configuration for the per-turn state layer.

Scope keys are namespaced under key_prefix. Storage-specific behavior, including expiry, is configured directly on the selected storage provider.

StopEvent

Event emitted when the app stops.

StreamCancelledError

Raised when a stream operation is attempted after the stream has been cancelled.

StreamNotAllowedError

Raised when streaming is not allowed for this user or bot.

StreamTimedOutError

Raised when the bot failed to complete streaming within the two-minute limit.

TeamsBotApplicationTelemetry

OpenTelemetry source names for the Teams app orchestration package.

TerminalStreamError

Base class for terminal streaming errors (HTTP 403) that should not be retried.

TokenValidator

JWT token validator using PyJWKClient for simplified validation.

Initialize the token validator.

TurnState

One state scope for a single turn.

Behaves like a dict but adds two things the loader relies on:

  • Dirty tracking — the loader compares the current contents to the loaded snapshot, so nested mutations are persisted without dirtying reads.

  • Sealing — at the end of a turn the scope is sealed; any later access raises TurnStateSealedError.

Values must be JSON-serializable. Each scope is encoded with json.dumps when it is saved, so store only JSON-native types (str, int, float, bool, None, list, dict). A non-serializable value (e.g. a datetime or a custom object) is accepted on assignment but raises TypeError later, when the turn is saved.

TurnStateContainer

The state scopes loaded for one turn, together with the identity they were loaded for.

conversation is always present. user is None when the activity has no from identity, so there is no per-user scope to load or persist.

conversation_id/user_id record the identity this container was loaded for. The loader reads them back off the container when saving, so a save can never be told to persist under a different key than it was loaded from. That guarantee is why they are read-only properties: rebinding either one mid-turn would redirect the save to a different conversation or user while the scopes still hold the original identity's data.

Only the identity is bound. conversation/user and the injected deleter/saver remain ordinary mutable attributes, and the TurnState scopes stay mutable for the whole turn, which is how seal() and delete() work.

Constructor arguments are keyword-only so the public constructor is not tied to positional order and can evolve without breaking callers.

TurnStateSealedError

Raised when a sealed TurnState is accessed after its turn ends.

Functions

Plugin

Turns any class into a plugin using the decorator pattern.

Plugin(name: str | None = None, version: str | None = None, description: str | None = None) -> Callable[[Type[T]], Type[T]]

Parameters

Name Description
name
Default value: None
version
Default value: None
description
Default value: None

agent365_baggage

agent365_baggage(source: Activity | _ActivityContextSource | None = None, *, include: Iterable[Literal['senderName', 'agentName', 'agentDescription', 'senderEmail', 'agentEmail']] | None = None, operation_source: str | int | float | None = None, channel_link: str | int | float | None = None, additional_baggage: Mapping[str, str | int | float | None] | None = None) -> Agent365Baggage

Parameters

Name Description
source
Default value: None

Keyword-Only Parameters

Name Description
include
Default value: None
operation_source
Default value: None
channel_link
Default value: None
additional_baggage
Default value: None

build_html_widget_markdown

Wraps an HTML widget payload in the >>``<<>>`<<html-widget markdown code fence format required by Teams to render the widget in a message.

Diagnostic: ExperimentalTeamsHtmlWidget

build_html_widget_markdown(payload: HtmlWidgetPayload, options: HtmlWidgetMarkdownOptions | None = None) -> str

Parameters

Name Description
payload
Required
options
Default value: None

build_html_widget_message

Builds a message activity containing an HTML widget, ready to be sent.

Diagnostic: ExperimentalTeamsHtmlWidget

build_html_widget_message(payload: HtmlWidgetPayload, options: HtmlWidgetMarkdownOptions | None = None) -> MessageActivityInput

Parameters

Name Description
payload
Required
options
Default value: None

create_agent365_scope

Create a reusable proactive Agent365 baggage scope opener.

create_agent365_scope(options: Agent365ScopeOptions | Literal[False] | None = None) -> Agent365ScopeOpener

Parameters

Name Description
options
Default value: None

create_state_loader

Resolve the App(state=...) option into a loader (or None when off).

state is the opt-in value: falsy disables state; True enables it with defaults; a StateOptions configures it. The loader's storage is the one on StateOptions when provided, otherwise the app's shared fallback_storage. A warning is logged when that resolves to in-memory LocalStorage.

create_state_loader(state: bool | StateOptions | None, fallback_storage: Storage[str, Any]) -> TurnStateLoader | None

Parameters

Name Description
state
Required
fallback_storage
Required

get_event_type_from_signature

Extract event type from function signature by inspecting the first parameter's type hint.

get_event_type_from_signature(func: Callable[[...], Any]) -> Literal['activity', 'error', 'start', 'stop', 'sign_in', 'sign_in_failure', 'activity_response', 'activity_sent'] | str | None

Parameters

Name Description
func
Required

Function to inspect

Returns

Type Description

Event type string if detectable, None otherwise

get_metadata

Get plugin metadata from a class.

get_metadata(cls: Type[PluginBase]) -> PluginOptions

Parameters

Name Description
cls
Required

inject_widget_protocol

Injects the MCP Apps protocol script into widget HTML.

This sets up:

  • The ui/initialize handshake (required for rendering)
  • Size reporting via ui/notifications/size-changed
  • Optional notification hooks (opt-in via notifications option)

If the HTML already contains the protocol (detected by 'ui/initialize'), it is returned unchanged.

Diagnostic: ExperimentalTeamsHtmlWidget

inject_widget_protocol(html: str, options: InjectWidgetProtocolOptions | None = None) -> str

Parameters

Name Description
html
Required
options
Default value: None

is_registered_event

Check if an event name is registered.

is_registered_event(event_name: str) -> bool

Parameters

Name Description
event_name
Required

Event name to check

Returns

Type Description

True if registered, False otherwise

to_threaded_conversation_id

Construct a threaded conversation ID by appending ;messageid={message_id} to the conversation ID. This is the format the service uses to route messages to a specific thread.

to_threaded_conversation_id(conversation_id: str, message_id: str) -> str

Parameters

Name Description
conversation_id
Required

The conversation to thread into (e.g. 19:abc@thread.skype)

message_id
Required

The thread root message ID (must be a non-zero numeric string)

Returns

Type Description
<xref:The> <xref:threaded> conversation <xref:ID> (<xref:e.g.> `<xref:19>

<xref:mailto:abc@thread.skype>;messageid=123`)

try_get_widget_model_context

Attempt to extract an MCP UI update-model-context request from a message activity's value.

A widget can request that content be added to the model context by reusing the messageBack mechanism (like Action.Submit for adaptive cards). Such a request arrives as a normal message activity whose value carries the McpUiUpdateModelContextRequest payload. This is fire-and-forget: the bot does not respond.

This helper is tolerant of two wire shapes:

  1. The raw request object ({"method": "ui/update-model-context", "params": ...}).

  2. An envelope of the form {"type": "widgetModelContext", "data": <request>}.

Diagnostic: ExperimentalTeamsHtmlWidget

try_get_widget_model_context(activity: Any) -> McpUiUpdateModelContextRequest | None

Parameters

Name Description
activity
Required

A message activity (or any object with a value attribute).

Returns

Type Description

The parsed request, or None if value is not a valid update-model-context request.

validate_remote_function_request

Validate JWT and extract client context from request headers for remote function calls.

async validate_remote_function_request(headers: Dict[str, str], entra_token_validator: TokenValidator | None) -> tuple[Optional[microsoft_teams.apps.contexts.client_context.ClientContext], Optional[str]]

Parameters

Name Description
headers
Required

Request headers dict.

entra_token_validator
Required

TokenValidator instance for Entra ID tokens.

Returns

Type Description

Tuple of (ClientContext, None) on success or (None, error_message) on failure.

validate_security_policy

Validates that external references in widget HTML are covered by the declared security policy. Returns a list of warnings for any references to origins not present in the appropriate policy field.

This is a static analysis tool - it cannot catch dynamically constructed URLs. Use the debug_csp_violations option on inject_widget_protocol for runtime detection.

Diagnostic: ExperimentalTeamsHtmlWidget

validate_security_policy(html: str, policy: HtmlWidgetSecurityPolicy) -> list[microsoft_teams.apps.utils.html_widget.SecurityPolicyWarning]

Parameters

Name Description
html
Required
policy
Required