Skip to content

Introduce HttpServer (and begin deprecating HttpPlugin)#433

Merged
heyitsaamir merged 51 commits into
mainfrom
httpAdapter
Mar 16, 2026
Merged

Introduce HttpServer (and begin deprecating HttpPlugin)#433
heyitsaamir merged 51 commits into
mainfrom
httpAdapter

Conversation

@heyitsaamir

@heyitsaamir heyitsaamir commented Jan 16, 2026

Copy link
Copy Markdown
Collaborator

In this PR, we introduce a new object called HttpServer and begin to deprecate HttpPlugin.

Main changes

  1. Create HttpServer internal class. It accepts an IHttpServerAdapter which is the server implementation.
  2. Pulled out the express implementation as an IHttpServerAdapter
  3. Deprecated HttpPlugin, and made it use HttpServer + ExpressAdapter.
  4. Changed BotBuilder/A2A/Mcp plugins to depend on HttpServer vs. HttpPlugin.
  5. Added examples to show how powerful IHttpServerAdapter can be with different types of servers (hono, fastify).
  6. Minor refactor of the jwt middleware such that we can reuse it in HttpServer and app.embed.

Why:

HTTP is a core part of our sdk. Our App object uses HTTP to set up a server, perform auth validations, and pipe the request to the handlers that are attached, and then return the response. Key part is that Http is a core part of App, not a plugin, since core functionality is dependent on it.
Even inside the App object, we were doing special casing for this Http"Plugin" whereas it should never have really been a plugin to begin with. By making it a plugin, we were exposing many non-plugin essential things to the plugin system in general.

So what should it have been? Well, HTTP Plugin had these responsibilities

  1. Set up the express server
  2. Perform validations if credentials were present
  3. Pass the incoming request to App
  4. Once App handlers have had a chance to process this incoming request, pass the response back to the server.

So, we introduce a new object called HttpServer whose responsibilities are essentially that ^. This object is not a plugin, but an object that's created by App itself.

Customization

Now this idealogical shift doesn't really warrant us doing this refactor, but we started seeing requests from folks who wanted to hook Teams functionality into existing servers, or replace the underlying server infra with a non-express server. Our recommendation was to rebuild a new HttpPlugin. But rebuilding this plugin is not simple (since we don't really document it anywhere, and didn't expect folks to build their own).
So HttpServer exposes an IHttpServerAdapter concept. To build the adapter, one simply needs to build out a handler for extracting request data, and a handler for responses. This means that you can build simple custom adapters for your own existing servers. (And if you don't pass one in, we'll build a default express one.) Examples of servers are in the http-adapters folder under examples/.

Adapter Interface

The IHttpServerAdapter interface adapters need to implement:

interface IHttpServerAdapter {
  registerRoute(method: HttpMethod, path: string, handler: HttpRouteHandler): void;
  serveStatic?(path: string, directory: string): void;
  start?(port: number): Promise<void>;
  stop?(): Promise<void>;
}

Handlers are pure functions — ({ body, headers }) → { status, body }. No framework-specific request/response objects leak through the abstraction.

Why registerRoute?

Some adapter patterns have the adapter own routing internally and just receive a single callback. But our SDK creates routes dynamically — app.function('myFunc') registers /api/functions/myFunc at runtime, in addition to the core /api/messages endpoint. The adapter needs a registerRoute method so that both HttpServer and app.function() can tell it what paths to listen on.

Optional methods

start/stop are optional — serverless adapters (Vercel, Lambda) don't need them. serveStatic is optional — only needed for tab hosting.

HttpMethod is currently just 'POST' (the only method the Teams protocol uses). It may expand to a union if needed.

Backward Compat

We've updated HttpPlugin to basically use HttpServer with an ExpressAdapter internally for backward compat. I don't think this should lead to any breaking changes (even if someone passes in their own HttpPlugin). (Tested BotBuilderPlugin, from examples, and it worked without any changes).
However, it should be noted that I marked HttpPlugin as deprecated in this PR, so it should be discouraged going forward, and after the next few versions, it'll be removed.

Testing

I tested by running the following examples:

  1. Echo bot
  2. Devtools
  3. BotBuilder
  4. HttpPlugin
  5. Tabs
  6. AI (streaming and regular completions)

skip-test-verification (added manifest for tabs)

PR Dependency Tree

PR Dependency Tree

This tree was auto-generated by Charcoal

@heyitsaamir
heyitsaamir force-pushed the httpAdapter branch 3 times, most recently from 6601a42 to 7e55c15 Compare January 17, 2026 07:13
@heyitsaamir heyitsaamir changed the title Introduce Configurable Http Plugin Introduce HttpServer (and begin deprecating HttpPlugin) Jan 20, 2026
Comment thread examples/http-adapters/README.md Outdated
Comment thread examples/http-adapters/README.md Outdated
Comment thread packages/apps/src/http/http-server.ts Outdated
Comment thread examples/http-adapters/package.json Outdated
Comment thread examples/http-adapters/express/teams-app.ts
@heyitsaamir
heyitsaamir force-pushed the httpAdapter branch 5 times, most recently from 4c1ca04 to 5422e29 Compare January 24, 2026 09:20

@heyitsaamir heyitsaamir left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Questions:

  1. Should we remove app.initialize()? I feel like we could remove it, but i like having it because it could give us a way to initialize things asynchronously if needed.
  2. Ideally we should not be shipping with a server at all -- If we want to do serve(new App()) where serve comes from an express specific package, that'll lead to a pretty big breaking change for all our docs for our simplest use-cases. For this reason, I think we should leave app.start the way it is, and for v3 consider removing .start.

Comment thread packages/apps/src/app.ts
Comment thread external/a2a/src/server/plugin.ts
Comment thread external/mcp/src/plugin.ts
Comment thread packages/apps/src/http/express-adapter.ts Outdated
Comment thread packages/apps/src/http/express-adapter.ts Outdated
Comment thread packages/apps/src/http/http-server.ts Outdated
Comment thread packages/apps/src/plugins/http/plugin.ts Outdated
Comment thread packages/apps/src/plugins/http/plugin.ts Outdated
@heyitsaamir
heyitsaamir force-pushed the httpAdapter branch 3 times, most recently from 4ec6679 to 95d91e9 Compare January 26, 2026 17:04
corinagum pushed a commit that referenced this pull request Feb 12, 2026
This PR upgrades our systems from express v4 to express v5.
The changes applicable to us are fairly minimal



#### PR Dependency Tree


* **PR #424**
  * **PR #433**
    * **PR #442** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)
Comment thread packages/apps/src/http/adapter.ts
Comment thread packages/apps/src/http/http-server.ts Outdated
Comment thread packages/apps/src/test-utils.ts
Comment thread packages/apps/src/http/http-server.ts
heyitsaamir added a commit that referenced this pull request Mar 11, 2026
This PR upgrades our systems from express v4 to express v5.
The changes applicable to us are fairly minimal



#### PR Dependency Tree


* **PR #424**
  * **PR #433**
    * **PR #442** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)
heyitsaamir added a commit that referenced this pull request Mar 12, 2026
This PR upgrades our systems from express v4 to express v5.
The changes applicable to us are fairly minimal



#### PR Dependency Tree


* **PR #424**
  * **PR #433**
    * **PR #442** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)
heyitsaamir and others added 22 commits March 16, 2026 12:02
This PR upgrades our systems from express v4 to express v5.
The changes applicable to us are fairly minimal

* **PR #424**
  * **PR #433**
    * **PR #442** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)
- Remove IRequestHelpers/IRouteConfig callback pattern — handlers are
  now pure functions: ({ body, headers }) → { status, body }
- Remove initialize() from adapter interface (all were no-ops)
- Rename to registerRoute(method, path, handler) with typed HttpMethod
- Type request/response bodies as unknown instead of any
- No breaking changes to ExpressAdapter or HttpPlugin public APIs

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Rename the interface and app option to better reflect that this is
a server-side HTTP adapter: IHttpAdapter → IHttpServerAdapter,
httpAdapter → httpServerAdapter.
Restify was the default HTTP server used by the Bot Framework JS SDK.
This example shows how to use it with teams.ts via IHttpServerAdapter.
…lugins

IHttpServer was unnecessary indirection — every plugin only used
httpServer.adapter. Now plugins inject the adapter directly via
@HttpServerAdapter() decorator. Also scopes express.json() and cors()
to only the routes that need them instead of applying globally.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…s, add backward compat JSON parsing

- Stop HTTP server in app.stop() and call stop() if start() fails
- Update deprecation messages to reference httpServerAdapter option
- Soften deprecation timeline to "future version"
- Add express.json() backward compat in deprecated HttpPlugin

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@heyitsaamir
heyitsaamir merged commit f7911b2 into main Mar 16, 2026
11 checks passed
@heyitsaamir
heyitsaamir deleted the httpAdapter branch March 16, 2026 19:53
@heyitsaamir heyitsaamir mentioned this pull request Mar 25, 2026
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants