Skip to main content
Upgrade an existing mcp-use 1.x server by updating the runtime, server entry, registrations, request context, security configuration, and widgets. Most server registrations keep the same concepts and require small syntax changes. Widgets require a complete rewrite as MCP App Views.
v2 is in beta. Some v1 capabilities do not have v2 equivalents yet. Review the current limitations before upgrading a production server.

Migration checklist

1

Update the runtime and server entry

Upgrade to Node.js >=22.22.2, use ESM, import from mcp-use, and default-export the server.
2

Update server registrations

Convert tools, resources, resource templates, and prompts to the definition-plus-callback API and return raw MCP results.
3

Update runtime behavior

Replace session assumptions, request context fields, authentication, notifications, elicitation, middleware, and deployment adapters.
4

Rebuild widgets as Views

Replace the widget file layout, tool binding, result helper, provider, generated helpers, hooks, state model, and asset paths.
5

Review beta limitations and verify

Check whether a missing v1 capability affects the server, then typecheck, build, run, and exercise the migrated project.

Update the runtime and entry point

The current v2 beta requires Node.js >=22.22.2 and ESM.
Import server APIs from mcp-use:
Default-export the server from index.ts.

Export every static tool

Assign every statically declared tool to an exported constant. If tools live in other modules, re-export them from the server entry:
Apply this rule to all static tools, not only tools currently bound to or called by a View. The root mcp-env.d.ts declaration registers typeof import("<server-entry>"). Only exported ToolRef values participate in View typing. This is a live type-only import, not the v1 tool-registry generator. mcp-use dev, build, and typecheck create or refresh the declaration, but they do not execute the server to generate tool-specific types. If the v1 server registers a tool from a loop, runtime configuration, or an OpenAPI document, it cannot export a static ToolRef. Call that tool from a View with explicit types:
Do not import a server-side ToolRef value into a file-based View. The View bundle must not include server code.

Migrate tools

Move the callback to the second argument, replace schema with inputSchema, and return a raw MCP result.
schema remains an alias for inputSchema in the current beta, but inputSchema matches the MCP wire field and is the migration target. Follow these result rules:
  • A successful tool with outputSchema must return matching structuredContent.
  • An error result may return isError: true without structured output.
  • For object-shaped structured output, include a text fallback in content.
  • Replace inputs[] with a Standard Schema-compatible input schema.
  • Do not chain server.tool(...).tool(...); tool() returns a ToolRef.
Response helpers such as text(), object(), array(), image(), and error() remain as deprecated upgrade shims. Prefer raw CallToolResult, ReadResourceResult, and GetPromptResult envelopes. Native array() does not preserve the v1 { data } wrapper.

Migrate resources and templates

Pass the reader as the second argument. A static resource callback receives (uri, ctx) and returns contents:
Remove inline readCallback and callbacks fields. For resource templates:
  • replace nested resourceTemplate with top-level uriTemplate
  • move callbacks.complete to top-level complete
  • pass the reader separately as (uri, params, ctx)
  • handle inferred template values as string | string[]
  • return raw contents

Migrate prompts

Keep schema for prompt arguments, pass the callback separately, and return raw messages:
Replace v1 args[] and inline cb. completable() supplies suggestions but does not constrain valid values. Apply field refinements before wrapping a schema with completable().

Update request context

v2 request context exists only for the current request. Remove session assumptions from client metadata, logging, progress, notifications, and elicitation. ctx.client.info(), capabilities(), can(), extension(), and user() return client-declared request hints. Never use them for authorization. Use verified ctx.auth data for identity and permissions.

Send notifications on the correct channel

v2 supports custom notifications during an active request:
Await the notification before the callback returns. It travels on the originating request’s response stream and cannot notify that client after the request finishes. Use the standard request-scoped and subscription APIs for their specific jobs:
The server helpers notify matching active subscription listeners. They do not provide arbitrary broadcast or session-targeted push.

Make elicitation replay-safe

v2 elicitation returns an input-required result and re-runs the handler when the client supplies input:
Use a stable key. Assume the handler can run more than once. Do not perform a side effect before accepted input is available.

Rebuild widgets as MCP App Views

Legacy widgets require a full UI migration. File discovery, binding, tool results, component lifecycle, hooks, state, assets, and typing all changed.

Move the files and binding

Move data previously passed as props to the tool result’s _meta field. Access it from useToolContext().meta in the View. _meta is View-only and is not validated or typed by outputSchema; validate or narrow it before use. Keep structuredContent for output that matches outputSchema and should also be visible to the model. The bound tool must:
  • export its ToolRef
  • declare an outputSchema
  • return matching structuredContent
  • move v1 widget({ props }) data to result _meta
  • return useful text content for the model and text-only hosts
  • bind to exactly one View with view: { name }
Each View can bind to at most one server tool. Create another View when a second tool needs a rendered result. Keep helper tools viewless and call them from the View with useCallTool(). Move resource facts such as description, csp, permissions, domain, and prefersBorder into the bound tool’s view configuration. Remove v1 invoking, invoked, and widgetAccessible; the native View configuration does not emit those OpenAI-specific overlay fields.

Replace widget hooks

Default-export the View component. It mounts once while the host connects and while tool input and result notifications arrive.
Use the focused v2 surface: viewConfig supports autoResize and displayModes. Both values below are the defaults, so omit the export when they are correct for the View:
displayModes must include "inline". Use useSendSizeChanged() only when autoResize is false and the View reports its size manually. Compose optional presentation components such as ThemeProvider, ViewControls, and your own error boundary. The framework owns the connection, bootstrap, and required top-level error boundary.

Migrate View state and model context

useViewState() requires an object default and shares one JSON-serializable snapshot across the mounted View. The state is model-visible. ChatGPT can restore View state across View lifetimes. Other MCP Apps hosts keep the state only for the current iframe lifetime. Use ModelContext or modelContext for model-visible natural-language context. Use useSendFollowUp() to trigger a new model turn. Keep presentation-only state in ordinary React state. useFiles() keeps the upload/download capability check, but it no longer accepts the v1 modelVisible option or mutates widget state automatically.

Update View assets

Native View documents are generated MCP resources. Do not register uiResource() or serve a separate HTML document. Move existing widget CSP domains to view.csp.

Update authentication, proxies, and security

Native v2 acts as an OAuth resource server backed by an external authorization server. Import provider adapters from mcp-use/oauth/*, supply their required locator options, and use the provider-specific ctx.auth.user type. Replace generic userId assumptions with the provider’s mapped field, commonly id. Replace getAuth, hasScope, and requireScope with verified ctx.auth, scopes, permissions, and application authorization checks. OAuth proxy or authorization-server mode has no native v2 migration. Do not translate oauthProxy, jwksVerifier, or mountOAuthProxy as resource-server configuration. v2 upstream composition accepts HTTP remotes or a ready compatible client connection. A v1 stdio child-process proxy requires an architecture change.

Preserve security semantics explicitly

The name allowedOrigins changed meaning: Map v1 CORS allowMethods and allowHeaders to v2 methods and allowedHeaders. Test Host rejection, Origin rejection, and CORS separately. Use basePath for the MCP route. Set MCP_URL for the externally visible server origin.

Review current beta limitations

The following v1 capabilities do not currently have direct v2 equivalents. Update the application design where one of these limitations affects your server.

Server lifecycle and transport

  • Session stores, active-session registries, stream managers, session recovery, and session affinity are not part of v2.
  • Arbitrary session-targeted and post-response push are not available. Request-scoped custom notifications and subscription invalidations remain available.
  • Server-to-client sampling through ctx.sample() is not available.
  • The v1 roots-changed callback surface is not available.
  • Express and Connect adapters are not available. Use Hono or server.fetch.
  • Stdio serving and stdio child-process proxy configuration do not have a native migration path.
  • CommonJS and unsupported Node.js versions are intentional compatibility breaks, not beta bugs.
Move durable state to application storage keyed by verified user, tenant, or an explicit domain handle. Do not key business state to an MCP transport session.

OAuth, proxy, and OpenAPI

  • OAuth proxy and authorization-server mode are deferred. Direct resource-server authentication is implemented.
  • Unsigned token bypasses such as verifyJwt: false are not supported.
  • Verify proxy requirements for upstream OAuth, templates, completions, subscriptions, list synchronization, sampling, and elicitation before migrating.
  • Verify OpenAPI servers that depend on external references, cookies, non-JSON request bodies, callbacks, webhooks, or automatic security-scheme discovery.

Views

  • Each View can bind to at most one server tool.
  • A bound tool requires outputSchema and matching structuredContent.
  • Static typing sees exported ToolRef values only.
  • Cross-lifetime useViewState() restoration is host-specific.
  • useFiles() is host-specific and must be capability-checked.
  • View resource facts are static per bound tool. v2 has no supported hook for rewriting domain or other View resource metadata per client.
  • Raw uiResource, @mcp-ui/server adapters, exposeAsTool, and a shared View bound to multiple server tools have no native equivalent.

Use the compatibility bridge only for staging

Existing servers can temporarily keep:
The deprecated bridge supports common v1 tools, resources, prompts, middleware, direct built-in OAuth providers, OpenAPI servers, response helpers, and one tool per legacy widget. The bridge does not provide sessions, sampling, post-response or session-targeted notifications, blocking elicitation, OAuth proxying, stdio proxying, raw UI resources, array-style schemas, unsigned-token bypasses, or a widget shared by multiple bound tools. Treat every bridge import as unfinished migration work. The bridge is planned for removal in mcp-use v3.

Verify the migration

1

Run a real TypeScript check

Run mcp-use typecheck, npm run typecheck, or the project’s actual tsc --noEmit command. mcp-use build bundles code but does not prove that v1 APIs are type-compatible.
2

Build and start the production output

Run the project’s production build, start the built server, and confirm the expected MCP route and public asset routes.
3

Exercise server primitives

Call at least one tool, read a static resource, complete and read a resource template, and get a prompt with a real client.
4

Render every View state

Verify pending, ready, and error states; matching structured output; theme; display mode; sizing; CSP; and public assets in a capable host.
5

Test security and authentication

Check a valid token, missing or invalid scopes, mapped user data, Host rejection, Origin rejection, and browser CORS behavior.
6

Preserve behavioral coverage

Keep existing runtime assertions as runtime assertions. If v2 does not support a tested behavior, leave that limitation explicit instead of replacing the test with source-text or artifact assertions.
7

Remove v1 leftovers

Remove remaining v1 imports, helpers, widget files, session APIs, sampling calls, stdio proxy configuration, and old security fields. Keep a mcp-use/server import only when you intentionally use the temporary compatibility bridge.

Continue with the v2 guides