mcp-use 2.0.0-beta.28 → 2.0.0-beta.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -29,10 +29,8 @@ import {
29
29
  originValidationMiddleware,
30
30
  pathUnderBase,
31
31
  pathnameOf,
32
- requireBearerAuth,
33
- routeFetch,
34
- toFrameworkHandler
35
- } from "./chunk-26JBVQUY.js";
32
+ requireBearerAuth
33
+ } from "./chunk-QKJJ6DWK.js";
36
34
  import {
37
35
  getOAuthProviderOptions,
38
36
  resolveConfiguredOAuthResource,
@@ -48,6 +46,7 @@ import {
48
46
  ResourceTemplate,
49
47
  isInputRequiredResult as isInputRequiredResult2
50
48
  } from "@modelcontextprotocol/server";
49
+ import { Hono } from "hono";
51
50
 
52
51
  // src/branding.ts
53
52
  var FAVICON_CACHE_CONTROL = "public, max-age=31536000, immutable";
@@ -87,10 +86,10 @@ function parseDataImage(source, field) {
87
86
  }
88
87
  try {
89
88
  if (parts.includes("base64")) {
90
- const binary = atob(payload);
89
+ const binary2 = atob(payload);
91
90
  return {
92
91
  mimeType,
93
- bytes: Uint8Array.from(binary, (character) => character.charCodeAt(0))
92
+ bytes: Uint8Array.from(binary2, (character) => character.charCodeAt(0))
94
93
  };
95
94
  }
96
95
  return {
@@ -323,6 +322,7 @@ import {
323
322
  inputRequired,
324
323
  inputResponse
325
324
  } from "@modelcontextprotocol/server";
325
+ import { HonoRequest } from "hono/request";
326
326
 
327
327
  // src/views/capabilities.ts
328
328
  import {
@@ -436,8 +436,10 @@ function createElicit(inputResponses) {
436
436
  };
437
437
  }
438
438
  function toRequestContext(ctx) {
439
- const request = ctx.http?.req;
440
- return {
439
+ const rawRequest = ctx.http?.req;
440
+ const http = rawRequest === void 0 ? void 0 : getRequestBag(rawRequest).honoContext;
441
+ const request = http?.req ?? (rawRequest === void 0 ? void 0 : new HonoRequest(rawRequest));
442
+ const additions = {
441
443
  signal: ctx.mcpReq.signal,
442
444
  ...request !== void 0 && { request },
443
445
  ...ctx.mcpReq.inputResponses !== void 0 && {
@@ -471,12 +473,18 @@ function toRequestContext(ctx) {
471
473
  });
472
474
  }
473
475
  };
476
+ if (http !== void 0) {
477
+ return Object.assign(http, additions);
478
+ }
479
+ return {
480
+ ...additions,
481
+ ...request !== void 0 && { req: request }
482
+ };
474
483
  }
475
484
  function toAuthenticatedRequestContext(ctx) {
476
485
  const authInfo = ctx.http?.authInfo;
477
486
  requireOAuthAuthInfo(authInfo);
478
- return {
479
- ...toRequestContext(ctx),
487
+ return Object.assign(toRequestContext(ctx), {
480
488
  auth: {
481
489
  user: authInfo.extra.user,
482
490
  payload: authInfo.extra.payload,
@@ -487,7 +495,84 @@ function toAuthenticatedRequestContext(ctx) {
487
495
  expiresAt: authInfo.expiresAt,
488
496
  ...authInfo.resource !== void 0 && { resource: authInfo.resource }
489
497
  }
490
- };
498
+ });
499
+ }
500
+
501
+ // src/response-conversion.ts
502
+ function isReadResourceResult(result) {
503
+ return "contents" in result && Array.isArray(result.contents);
504
+ }
505
+ function isGetPromptResult(result) {
506
+ return "messages" in result && Array.isArray(result.messages);
507
+ }
508
+ function toResourceResult(result, uri) {
509
+ if (isReadResourceResult(result)) {
510
+ return result;
511
+ }
512
+ const mime = result._meta && typeof result._meta === "object" && typeof result._meta.mimeType === "string" ? result._meta.mimeType : void 0;
513
+ const contents = [];
514
+ for (const block of result.content ?? []) {
515
+ const mapped = contentBlockToResourceContents(block, uri, mime);
516
+ if (mapped !== void 0) {
517
+ contents.push(mapped);
518
+ }
519
+ }
520
+ if (contents.length === 0 && result.structuredContent !== void 0) {
521
+ contents.push({
522
+ uri,
523
+ mimeType: "application/json",
524
+ text: JSON.stringify(result.structuredContent)
525
+ });
526
+ }
527
+ if (contents.length === 0) {
528
+ contents.push({ uri, mimeType: "text/plain", text: "" });
529
+ }
530
+ return { contents };
531
+ }
532
+ function contentBlockToResourceContents(block, uri, mimeHint) {
533
+ if (block.type === "text") {
534
+ return {
535
+ uri,
536
+ mimeType: mimeHint ?? "text/plain",
537
+ text: block.text
538
+ };
539
+ }
540
+ if (block.type === "image" || block.type === "audio") {
541
+ return {
542
+ uri,
543
+ mimeType: block.mimeType,
544
+ blob: block.data
545
+ };
546
+ }
547
+ if (block.type === "resource") {
548
+ return { ...block.resource };
549
+ }
550
+ return void 0;
551
+ }
552
+ function toPromptResult(result) {
553
+ if (isGetPromptResult(result)) {
554
+ return result;
555
+ }
556
+ const messages = (result.content ?? []).map((content) => ({
557
+ role: "user",
558
+ content
559
+ }));
560
+ if (messages.length === 0 && result.structuredContent !== void 0) {
561
+ messages.push({
562
+ role: "user",
563
+ content: {
564
+ type: "text",
565
+ text: JSON.stringify(result.structuredContent)
566
+ }
567
+ });
568
+ }
569
+ if (messages.length === 0) {
570
+ messages.push({
571
+ role: "user",
572
+ content: { type: "text", text: "" }
573
+ });
574
+ }
575
+ return { messages };
491
576
  }
492
577
 
493
578
  // src/middleware/cors.ts
@@ -677,7 +762,10 @@ function composeMiddleware(entries, method, innerFn) {
677
762
  return innerFn();
678
763
  }
679
764
  const entry = matching[i];
680
- return entry.handler(ctx, () => dispatch(i + 1));
765
+ return entry.handler(
766
+ ctx,
767
+ () => dispatch(i + 1)
768
+ );
681
769
  };
682
770
  return dispatch(0);
683
771
  };
@@ -687,6 +775,7 @@ function freezeMiddlewareContext(ctx) {
687
775
  method: ctx.method,
688
776
  params: Object.freeze({ ...ctx.params }),
689
777
  ...ctx.request !== void 0 && { request: ctx.request },
778
+ ...ctx.req !== void 0 && { req: ctx.req },
690
779
  ...ctx.session !== void 0 && {
691
780
  session: Object.freeze({ ...ctx.session })
692
781
  },
@@ -758,10 +847,10 @@ function dispatchMcpEvents(events, method, phase, ctx, result) {
758
847
  }
759
848
  try {
760
849
  entry.handler(frozen, result);
761
- } catch (error) {
850
+ } catch (error2) {
762
851
  console.error(
763
852
  `[mcp-use] MCP event listener for "${entry.pattern}" (${phase}) threw:`,
764
- error
853
+ error2
765
854
  );
766
855
  }
767
856
  }
@@ -791,7 +880,7 @@ function colorsEnabled() {
791
880
  return process.stdout?.isTTY === true;
792
881
  }
793
882
  function ansi(open, close) {
794
- return (text) => colorsEnabled() ? `\x1B[${open}m${text}\x1B[${close}m` : text;
883
+ return (text2) => colorsEnabled() ? `\x1B[${open}m${text2}\x1B[${close}m` : text2;
795
884
  }
796
885
  var bold = ansi(1, 22);
797
886
  var dim = ansi(2, 22);
@@ -849,13 +938,13 @@ function formatDetail(message) {
849
938
  }
850
939
  var INLINE_JSON_MAX_LENGTH = 80;
851
940
  function inlineJson(value) {
852
- let text;
941
+ let text2;
853
942
  try {
854
- text = JSON.stringify(value) ?? String(value);
943
+ text2 = JSON.stringify(value) ?? String(value);
855
944
  } catch {
856
- text = String(value);
945
+ text2 = String(value);
857
946
  }
858
- return text.length > INLINE_JSON_MAX_LENGTH ? `${text.slice(0, INLINE_JSON_MAX_LENGTH)}...` : text;
947
+ return text2.length > INLINE_JSON_MAX_LENGTH ? `${text2.slice(0, INLINE_JSON_MAX_LENGTH)}...` : text2;
859
948
  }
860
949
  function formatClientIdentity(message) {
861
950
  const meta = message.params?._meta;
@@ -866,8 +955,8 @@ function formatClientIdentity(message) {
866
955
  }
867
956
  return formatClientInfo(info);
868
957
  }
869
- function sanitize(text) {
870
- return text.replace(/[\u0000-\u001F\u007F-\u009F]+/g, " ");
958
+ function sanitize(text2) {
959
+ return text2.replace(/[\u0000-\u001F\u007F-\u009F]+/g, " ");
871
960
  }
872
961
  function methodStyle(method) {
873
962
  if (method.startsWith("tools/")) return cyan;
@@ -893,13 +982,13 @@ function redactHeaders(headers) {
893
982
  }
894
983
  async function extractResponseOutcome(res) {
895
984
  if (!res.body) return { errorMessage: null };
896
- let text;
985
+ let text2;
897
986
  try {
898
- text = await res.clone().text();
987
+ text2 = await res.clone().text();
899
988
  } catch {
900
989
  return { errorMessage: null };
901
990
  }
902
- if (!text) return { errorMessage: null };
991
+ if (!text2) return { errorMessage: null };
903
992
  const isSse = (res.headers.get("content-type") ?? "").includes(
904
993
  "text/event-stream"
905
994
  );
@@ -911,14 +1000,14 @@ async function extractResponseOutcome(res) {
911
1000
  }
912
1001
  };
913
1002
  if (isSse) {
914
- for (const line of text.split(/\r?\n/)) {
1003
+ for (const line of text2.split(/\r?\n/)) {
915
1004
  if (line.startsWith("data:")) {
916
1005
  const data = line.slice(5).trim();
917
1006
  if (data) tryParse(data);
918
1007
  }
919
1008
  }
920
1009
  } else {
921
- tryParse(text);
1010
+ tryParse(text2);
922
1011
  }
923
1012
  let result;
924
1013
  for (const payload of payloads) {
@@ -1002,17 +1091,17 @@ ${cyan("=".repeat(80))}`);
1002
1091
  console.log(`${yellow("Response Body:")} (no body)`);
1003
1092
  } else {
1004
1093
  try {
1005
- const text = await response.clone().text();
1006
- if (text.length === 0) {
1094
+ const text2 = await response.clone().text();
1095
+ if (text2.length === 0) {
1007
1096
  console.log(`${yellow("Response Body:")} (empty)`);
1008
1097
  } else {
1009
1098
  console.log(yellow("Response Body:"));
1010
1099
  try {
1011
- console.log(formatForDump(JSON.parse(text)));
1100
+ console.log(formatForDump(JSON.parse(text2)));
1012
1101
  } catch {
1013
1102
  console.log(
1014
- text.length > DUMP_BODY_MAX_LENGTH ? `${text.slice(0, DUMP_BODY_MAX_LENGTH)}
1015
- ... (truncated, ${text.length - DUMP_BODY_MAX_LENGTH} more characters)` : text
1103
+ text2.length > DUMP_BODY_MAX_LENGTH ? `${text2.slice(0, DUMP_BODY_MAX_LENGTH)}
1104
+ ... (truncated, ${text2.length - DUMP_BODY_MAX_LENGTH} more characters)` : text2
1016
1105
  );
1017
1106
  }
1018
1107
  }
@@ -1024,11 +1113,11 @@ ${cyan("=".repeat(80))}`);
1024
1113
  `);
1025
1114
  }
1026
1115
  function styleStatus(status) {
1027
- const text = String(status);
1028
- if (status >= 500) return magenta(text);
1029
- if (status >= 400) return red(text);
1030
- if (status >= 300) return yellow(text);
1031
- return green(text);
1116
+ const text2 = String(status);
1117
+ if (status >= 500) return magenta(text2);
1118
+ if (status >= 400) return red(text2);
1119
+ if (status >= 300) return yellow(text2);
1120
+ return green(text2);
1032
1121
  }
1033
1122
  function isNoisyRequest(httpMethod, pathname) {
1034
1123
  if (httpMethod !== "GET" && httpMethod !== "HEAD") return false;
@@ -1198,8 +1287,8 @@ function resolvePublicBase(assetsBase, basePath) {
1198
1287
  function escapeInlineScript(code) {
1199
1288
  return code.replaceAll(/<\/script/gi, "<\\/script").replaceAll("<!--", "\\x3C!--");
1200
1289
  }
1201
- function escapeInlineStyle(css) {
1202
- return css.replaceAll(/<\/style/gi, "<\\/style");
1290
+ function escapeInlineStyle(css2) {
1291
+ return css2.replaceAll(/<\/style/gi, "<\\/style");
1203
1292
  }
1204
1293
  function escapeHtml(value) {
1205
1294
  return value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
@@ -1520,6 +1609,16 @@ function omitToolSchemaDialects(tools) {
1520
1609
  ...tool.outputSchema === void 0 ? {} : { outputSchema: omitRootSchemaDialect(tool.outputSchema) }
1521
1610
  }));
1522
1611
  }
1612
+ function registerFetchMiddleware(app, middleware) {
1613
+ app.use("*", async (context, next) => {
1614
+ const response = await middleware(context.req.raw, async () => {
1615
+ await next();
1616
+ return context.res;
1617
+ });
1618
+ context.res = response;
1619
+ return response;
1620
+ });
1621
+ }
1523
1622
  var MCPServer = class _MCPServer {
1524
1623
  #config;
1525
1624
  #branding;
@@ -1540,7 +1639,9 @@ var MCPServer = class _MCPServer {
1540
1639
  /** Project root for filesystem-backed view bundle and public routes. */
1541
1640
  #viewsProjectRoot = process.cwd();
1542
1641
  #fetchHandler;
1642
+ #httpApp;
1543
1643
  #handler;
1644
+ #eventBus;
1544
1645
  #httpServer;
1545
1646
  #oauthResource;
1546
1647
  #oauthResourceResolved = false;
@@ -1555,6 +1656,30 @@ var MCPServer = class _MCPServer {
1555
1656
  #proxyOperations = /* @__PURE__ */ new Set();
1556
1657
  /** Whether terminal shutdown has begun. */
1557
1658
  #closed = false;
1659
+ /** Hono application that owns HTTP middleware and routes. */
1660
+ app;
1661
+ /** Register a typed `GET` route on {@link MCPServer.app}. */
1662
+ get;
1663
+ /** Register a typed `POST` route on {@link MCPServer.app}. */
1664
+ post;
1665
+ /** Register a typed `PUT` route on {@link MCPServer.app}. */
1666
+ put;
1667
+ /** Register a typed `PATCH` route on {@link MCPServer.app}. */
1668
+ patch;
1669
+ /** Register a typed `DELETE` route on {@link MCPServer.app}. */
1670
+ delete;
1671
+ /** Register a typed route for every HTTP method on {@link MCPServer.app}. */
1672
+ all;
1673
+ /**
1674
+ * Canonical Web-standard handler for edge runtimes and framework mounting.
1675
+ *
1676
+ * @example
1677
+ * ```ts
1678
+ * export default server;
1679
+ * // or: export const POST = server.fetch;
1680
+ * ```
1681
+ */
1682
+ fetch;
1558
1683
  /**
1559
1684
  * Create an MCP server from a parsed, bundled OpenAPI document.
1560
1685
  *
@@ -1589,22 +1714,37 @@ var MCPServer = class _MCPServer {
1589
1714
  * is both the MCP route and the path of the OAuth protected-resource
1590
1715
  * identity, so any explicit OAuth resource URL must use that exact path.
1591
1716
  * Nothing binds or listens until {@link MCPServer.listen} or
1592
- * {@link MCPServer.getHandler} is called.
1717
+ * the first request reaches {@link MCPServer.fetch}.
1593
1718
  */
1594
1719
  constructor(config) {
1595
1720
  assertServerConfig(config);
1596
1721
  this.#config = config;
1597
1722
  this.#branding = normalizeServerBranding(config);
1723
+ this.app = new Hono();
1724
+ this.app.use("*", async (context, next) => {
1725
+ getRequestBag(context.req.raw).honoContext = context;
1726
+ await next();
1727
+ });
1728
+ this.get = this.app.get.bind(this.app);
1729
+ this.post = this.app.post.bind(this.app);
1730
+ this.put = this.app.put.bind(this.app);
1731
+ this.patch = this.app.patch.bind(this.app);
1732
+ this.delete = this.app.delete.bind(this.app);
1733
+ this.all = this.app.all.bind(this.app);
1734
+ this.fetch = async (request, env, executionCtx) => {
1735
+ this.#ensureMounted("handler");
1736
+ return this.#httpApp.fetch(request, env, executionCtx);
1737
+ };
1598
1738
  if (config.oauth !== void 0) {
1599
1739
  const mcpUrl = typeof process === "undefined" ? void 0 : process.env["MCP_URL"];
1600
- const resource = resolveConfiguredOAuthResource({
1740
+ const resource2 = resolveConfiguredOAuthResource({
1601
1741
  provider: config.oauth,
1602
1742
  basePath: this.#basePath(),
1603
1743
  ...mcpUrl !== void 0 && { mcpUrl }
1604
1744
  });
1605
- this.#oauthResource = resource;
1606
- this.#oauthResourceResolved = resource !== void 0;
1607
- this.#oauthResourceConfigurationAbsent = resource === void 0;
1745
+ this.#oauthResource = resource2;
1746
+ this.#oauthResourceResolved = resource2 !== void 0;
1747
+ this.#oauthResourceConfigurationAbsent = resource2 === void 0;
1608
1748
  }
1609
1749
  }
1610
1750
  /**
@@ -1643,11 +1783,19 @@ var MCPServer = class _MCPServer {
1643
1783
  get branding() {
1644
1784
  return this.#branding;
1645
1785
  }
1786
+ /** @deprecated Use {@link MCPServer.fetch} directly. */
1787
+ getHandler() {
1788
+ return this.fetch;
1789
+ }
1646
1790
  /**
1647
1791
  * Register a tool. Input is validated against `inputSchema` before the callback
1648
1792
  * runs; results carrying `structuredContent` are type-checked against
1649
1793
  * `outputSchema` at the callback's return position.
1650
1794
  *
1795
+ * Assign static registrations to exported constants so `mcp-env.d.ts` can
1796
+ * expose their {@link ToolRef} types to views:
1797
+ * `export const search = server.tool(...)`.
1798
+ *
1651
1799
  * @returns A {@link ToolRef} carrying the tool name and phantom types for
1652
1800
  * inference-based view typing.
1653
1801
  */
@@ -1745,7 +1893,7 @@ var MCPServer = class _MCPServer {
1745
1893
  async proxy(input) {
1746
1894
  this.#assertOpen("proxy()");
1747
1895
  const operation = (async () => {
1748
- const { isProxyConnection, mountProxyConnection, mountProxyServers } = await import("./mcp-proxy-QYZQ6LNV.js");
1896
+ const { isProxyConnection, mountProxyConnection, mountProxyServers } = await import("./mcp-proxy-JK7IC5CR.js");
1749
1897
  if (isProxyConnection(input)) {
1750
1898
  await mountProxyConnection(this.#proxyHost(), input);
1751
1899
  return;
@@ -1759,70 +1907,20 @@ var MCPServer = class _MCPServer {
1759
1907
  this.#proxyOperations.delete(operation);
1760
1908
  }
1761
1909
  }
1762
- /**
1763
- * Web-standard request handler for the whole app (MCP endpoint included) —
1764
- * usable directly on serverless/edge runtimes or in tests.
1765
- *
1766
- * The handler never binds a socket, so no Host/Origin validation applies
1767
- * by default: DNS rebinding targets locally bound servers, and platform
1768
- * edges (Vercel, Cloudflare, …) only route hostnames assigned to the
1769
- * deployment. Set `allowedHosts`/`allowedOrigins` to opt into validation
1770
- * (additive — localhost-class values stay allowed).
1771
- *
1772
- * Pass the same `bus` to multiple server instances when their handlers
1773
- * replace one another while existing `subscriptions/listen` streams remain
1774
- * open. The bus is fixed when this instance first mounts.
1775
- *
1776
- * @param options - Optional handler wiring.
1777
- *
1778
- * @example
1779
- * ```ts
1780
- * const handler = server.getHandler();
1781
- * export default { fetch: handler };
1782
- * ```
1783
- */
1784
- getHandler(options = {}) {
1785
- this.#assertOpen("getHandler()");
1786
- const { fetch } = this.#ensureMounted("handler", void 0, options.bus);
1787
- return toFrameworkHandler(fetch);
1788
- }
1789
- /**
1790
- * Node `(req, res) => void` handler for composing with an existing
1791
- * `http.Server`. Uses the same internal `toNodeHandler` bridge as
1792
- * {@link MCPServer.listen}; MCPServer users do not need to import
1793
- * `mcp-use/node`.
1794
- *
1795
- * @example
1796
- * ```ts
1797
- * import { createServer } from "node:http";
1798
- * const httpServer = createServer(await server.getNodeHandler());
1799
- * httpServer.listen(3000);
1800
- * ```
1801
- */
1802
- async getNodeHandler() {
1803
- const { fetch } = this.#ensureMounted("handler");
1804
- const { toNodeHandler } = await import("./node-bridge.js");
1805
- return toNodeHandler({ fetch });
1806
- }
1807
- /**
1808
- * Register MCP operation middleware that intercepts JSON-RPC dispatch.
1809
- *
1810
- * Patterns use an `mcp:` prefix (for example `mcp:tools/call`, `mcp:*`).
1811
- * Exact methods may transform their typed result. The global `mcp:*` pattern
1812
- * is pass-through middleware. Middleware runs in registration order; call
1813
- * `next()` to continue the chain.
1814
- *
1815
- * @example
1816
- * ```ts
1817
- * server.use("mcp:tools/call", async (ctx, next) => {
1818
- * console.log(`Calling tool: ${ctx.params.name}`);
1819
- * return next();
1820
- * });
1821
- * ```
1822
- */
1823
- use(pattern, handler) {
1824
- this.#assertNotStarted("middleware", pattern);
1825
- this.#mcpMiddlewares.push(createMcpMiddlewareEntry(pattern, handler));
1910
+ use(patternOrHandler, ...handlers) {
1911
+ if (typeof patternOrHandler === "string" && patternOrHandler.startsWith("mcp:")) {
1912
+ this.#assertNotStarted("middleware", patternOrHandler);
1913
+ const handler = handlers[0];
1914
+ this.#mcpMiddlewares.push(
1915
+ createMcpMiddlewareEntry(
1916
+ patternOrHandler,
1917
+ handler
1918
+ )
1919
+ );
1920
+ return this;
1921
+ }
1922
+ const register = this.app.use;
1923
+ register.call(this.app, patternOrHandler, ...handlers);
1826
1924
  return this;
1827
1925
  }
1828
1926
  /**
@@ -1845,6 +1943,20 @@ var MCPServer = class _MCPServer {
1845
1943
  this.#mcpEventListeners.push(createMcpEventListenerEntry(pattern, handler));
1846
1944
  return this;
1847
1945
  }
1946
+ /**
1947
+ * Attach the shared development event bus before the first request.
1948
+ *
1949
+ * @param bus - Bus retained across hot-reloaded server instances.
1950
+ * @internal
1951
+ */
1952
+ __setEventBus(bus) {
1953
+ this.#assertNotStarted("event bus", "shared");
1954
+ this.#eventBus = bus;
1955
+ }
1956
+ /** Mount and validate the Hono/MCP application without serving a request. @internal */
1957
+ __mount() {
1958
+ this.#ensureMounted("handler");
1959
+ }
1848
1960
  /**
1849
1961
  * Publish a tools-list change to v2 clients with active subscriptions.
1850
1962
  *
@@ -1908,7 +2020,7 @@ var MCPServer = class _MCPServer {
1908
2020
  * requests accepted before then are queued. Public/wildcard listeners must
1909
2021
  * configure the resource before calling this method.
1910
2022
  *
1911
- * @throws If called on a localhost-class bind after {@link MCPServer.getHandler}
2023
+ * @throws If called on a localhost-class bind after {@link MCPServer.fetch}
1912
2024
  * already mounted the app without Host validation.
1913
2025
  */
1914
2026
  async listen(port = void 0, options = {}) {
@@ -1929,12 +2041,12 @@ var MCPServer = class _MCPServer {
1929
2041
  );
1930
2042
  void fetchReady.catch(() => void 0);
1931
2043
  let settled = false;
1932
- const rejectAndClose = (error) => {
2044
+ const rejectAndClose = (error2) => {
1933
2045
  if (!settled) {
1934
2046
  settled = true;
1935
- reject(error);
2047
+ reject(error2);
1936
2048
  }
1937
- rejectFetch?.(error);
2049
+ rejectFetch?.(error2);
1938
2050
  void new Promise(
1939
2051
  (closeResolve) => server.close(() => closeResolve())
1940
2052
  ).catch(() => void 0).finally(() => {
@@ -1954,13 +2066,7 @@ var MCPServer = class _MCPServer {
1954
2066
  try {
1955
2067
  const address = server.address();
1956
2068
  const boundPort = typeof address === "object" && address !== null ? address.port : requestedPort;
1957
- const { fetch } = this.#ensureMounted(
1958
- "listen",
1959
- boundPort,
1960
- void 0,
1961
- options.routes,
1962
- host
1963
- );
2069
+ const { fetch } = this.#ensureMounted("listen", boundPort, host);
1964
2070
  resolveFetch?.(fetch);
1965
2071
  if (!settled) {
1966
2072
  settled = true;
@@ -1969,8 +2075,8 @@ var MCPServer = class _MCPServer {
1969
2075
  url: `http://localhost:${boundPort}${this.#basePath()}`
1970
2076
  });
1971
2077
  }
1972
- } catch (error) {
1973
- rejectAndClose(error);
2078
+ } catch (error2) {
2079
+ rejectAndClose(error2);
1974
2080
  }
1975
2081
  });
1976
2082
  this.#httpServer = server;
@@ -1980,7 +2086,7 @@ var MCPServer = class _MCPServer {
1980
2086
  * Abort in-flight MCP exchanges and stop the HTTP listener.
1981
2087
  *
1982
2088
  * A closed server is done for good — the underlying MCP handler stays
1983
- * closed, so `listen()`/`getHandler()` cannot revive it. Create a new
2089
+ * closed, so `listen()`/`fetch()` cannot revive it. Create a new
1984
2090
  * instance to serve again.
1985
2091
  */
1986
2092
  async close() {
@@ -1996,8 +2102,8 @@ var MCPServer = class _MCPServer {
1996
2102
  }
1997
2103
  try {
1998
2104
  await this.#handler?.close();
1999
- } catch (error) {
2000
- errors.push(error);
2105
+ } catch (error2) {
2106
+ errors.push(error2);
2001
2107
  }
2002
2108
  const httpServer = this.#httpServer;
2003
2109
  if (httpServer !== void 0) {
@@ -2006,8 +2112,8 @@ var MCPServer = class _MCPServer {
2006
2112
  httpServer.close((err) => err ? reject(err) : resolve());
2007
2113
  });
2008
2114
  this.#httpServer = void 0;
2009
- } catch (error) {
2010
- errors.push(error);
2115
+ } catch (error2) {
2116
+ errors.push(error2);
2011
2117
  }
2012
2118
  }
2013
2119
  if (errors.length > 0) {
@@ -2042,7 +2148,7 @@ var MCPServer = class _MCPServer {
2042
2148
  return this.#oauthResource;
2043
2149
  }
2044
2150
  throw new Error(
2045
- "OAuth requires an explicit resource or MCP_URL when using getHandler() or listening on a non-local host"
2151
+ "OAuth requires an explicit resource or MCP_URL when using server.fetch or listening on a non-local host"
2046
2152
  );
2047
2153
  }
2048
2154
  #assertListenOAuthConfiguration(host) {
@@ -2061,7 +2167,7 @@ var MCPServer = class _MCPServer {
2061
2167
  #assertNotStarted(kind, name) {
2062
2168
  if (this.#handler !== void 0) {
2063
2169
  throw new Error(
2064
- `Cannot register ${kind} "${name}" after the server has started: registrations are replayed per request from the registry, so register everything before listen()/getHandler().`
2170
+ `Cannot register ${kind} "${name}" after the server has started: registrations are replayed per request from the registry, so register everything before listen()/server.fetch.`
2065
2171
  );
2066
2172
  }
2067
2173
  }
@@ -2104,7 +2210,7 @@ var MCPServer = class _MCPServer {
2104
2210
  * Configured lists are additive to the localhost-class allowlists, so local
2105
2211
  * runs keep working when a deployment hostname is added. With nothing
2106
2212
  * configured, `listen()` on a localhost-class bind validates Host against the
2107
- * localhost lists (the DNS-rebinding threat model), while `getHandler()` —
2213
+ * localhost lists (the DNS-rebinding threat model), while `server.fetch` —
2108
2214
  * which never binds — applies no validation. Origin validation is off unless
2109
2215
  * `allowedOrigins` is set explicitly (SDK-aligned: the handler is open by
2110
2216
  * default). When enabled, Origin is checked only on non-GET/HEAD requests.
@@ -2117,12 +2223,13 @@ var MCPServer = class _MCPServer {
2117
2223
  const origins = allowedOrigins !== void 0 ? [.../* @__PURE__ */ new Set([...localhostAllowedOrigins(), ...allowedOrigins])] : void 0;
2118
2224
  return { hosts, origins };
2119
2225
  }
2120
- #ensureMounted(mode, listenPort, bus, additionalRoutes = [], listenHost) {
2226
+ #ensureMounted(mode, listenPort, listenHost) {
2121
2227
  this.#assertOpen();
2122
2228
  if (this.#fetchHandler === void 0 || this.#handler === void 0) {
2123
2229
  const { hosts, origins } = this.#validationPolicy(mode, listenHost);
2124
2230
  const basePath = this.#basePath();
2125
2231
  const nestedBasePath = basePath === "/" ? "" : basePath;
2232
+ const httpApp = new Hono();
2126
2233
  const middlewares = [
2127
2234
  jsonBodyMiddleware(),
2128
2235
  requestLogger(this.#config.logging)
@@ -2146,35 +2253,38 @@ var MCPServer = class _MCPServer {
2146
2253
  }
2147
2254
  }
2148
2255
  this.#validateViewBindingsAtMount();
2149
- const resource = this.#resolveOAuthResource(mode, listenPort, listenHost);
2150
- if (resource !== void 0) {
2256
+ const resource2 = this.#resolveOAuthResource(mode, listenPort, listenHost);
2257
+ if (resource2 !== void 0) {
2151
2258
  const provider = this.#config.oauth;
2152
- middlewares.push(oauthMetadata(provider, resource));
2259
+ middlewares.push(oauthMetadata(provider, resource2));
2260
+ }
2261
+ for (const middleware of middlewares) {
2262
+ registerFetchMiddleware(httpApp, middleware);
2153
2263
  }
2154
2264
  const { handler, fetch: mcpFetch } = createMcpMount(
2155
2265
  (ctx) => this.#buildSdkServer(ctx),
2156
2266
  {
2157
2267
  path: basePath,
2158
- ...(this.#config.legacy !== void 0 || bus !== void 0) && {
2268
+ ...(this.#config.legacy !== void 0 || this.#eventBus !== void 0) && {
2159
2269
  handler: {
2160
2270
  ...this.#config.legacy !== void 0 && {
2161
2271
  legacy: this.#config.legacy
2162
2272
  },
2163
- ...bus !== void 0 && { bus }
2273
+ ...this.#eventBus !== void 0 && { bus: this.#eventBus }
2164
2274
  }
2165
2275
  },
2166
- ...resource !== void 0 && {
2276
+ ...resource2 !== void 0 && {
2167
2277
  authInfo: (request) => authInfoFromRequest(request)
2168
2278
  }
2169
2279
  }
2170
2280
  );
2171
2281
  let protectWithBearer = async (_request, next) => next();
2172
- if (resource !== void 0) {
2282
+ if (resource2 !== void 0) {
2173
2283
  const provider = this.#config.oauth;
2174
2284
  const providerOptions = getOAuthProviderOptions(provider);
2175
2285
  const gate = requireBearerAuth({
2176
- verifier: wrapOAuthTokenVerifier(provider, resource),
2177
- resourceMetadataUrl: getOAuthProtectedResourceMetadataUrl(resource),
2286
+ verifier: wrapOAuthTokenVerifier(provider, resource2),
2287
+ resourceMetadataUrl: getOAuthProtectedResourceMetadataUrl(resource2),
2178
2288
  ...providerOptions.requiredScopes !== void 0 && {
2179
2289
  requiredScopes: providerOptions.requiredScopes
2180
2290
  }
@@ -2206,12 +2316,11 @@ var MCPServer = class _MCPServer {
2206
2316
  this.#resources.values()
2207
2317
  );
2208
2318
  };
2209
- if (resource !== void 0 && this.#config.publicLandingPage !== true) {
2319
+ if (resource2 !== void 0 && this.#config.publicLandingPage !== true) {
2210
2320
  return protectWithBearer(request, respond);
2211
2321
  }
2212
2322
  return respond();
2213
2323
  };
2214
- const routes = [...additionalRoutes];
2215
2324
  const brandingDevMode = this.#viewsPrimed ? this.#viewsDevMode : process.env["NODE_ENV"] !== "production";
2216
2325
  const faviconHandler = createFaviconHandler(this.#branding, {
2217
2326
  dev: brandingDevMode,
@@ -2219,10 +2328,10 @@ var MCPServer = class _MCPServer {
2219
2328
  deferCors: deferViewCors
2220
2329
  });
2221
2330
  if (faviconHandler !== void 0) {
2222
- routes.push({
2223
- match: (request) => new URL(request.url).pathname === "/favicon.ico",
2224
- handler: faviconHandler
2225
- });
2331
+ this.app.all(
2332
+ "/favicon.ico",
2333
+ (context) => faviconHandler(context.req.raw)
2334
+ );
2226
2335
  }
2227
2336
  const viewHandler = createViewPublicHandler(basePath, this.#views, {
2228
2337
  dev: this.#viewsPrimed ? this.#viewsDevMode : brandingDevMode,
@@ -2231,12 +2340,11 @@ var MCPServer = class _MCPServer {
2231
2340
  deferCors: deferViewCors
2232
2341
  });
2233
2342
  if (viewHandler !== void 0) {
2234
- routes.push({
2235
- match: (request) => request.method === "GET" || request.method === "HEAD" ? new URL(request.url).pathname.startsWith(
2236
- `${nestedBasePath}/_mcp-use/public/`
2237
- ) : false,
2238
- handler: viewHandler
2239
- });
2343
+ this.app.on(
2344
+ ["GET", "HEAD"],
2345
+ `${nestedBasePath}/_mcp-use/public/*`,
2346
+ (context) => viewHandler(context.req.raw)
2347
+ );
2240
2348
  }
2241
2349
  if (!this.#viewsDevMode) {
2242
2350
  const viewAssetsHandler = createViewAssetsHandler(
@@ -2245,29 +2353,22 @@ var MCPServer = class _MCPServer {
2245
2353
  { projectRoot: this.#viewsProjectRoot, deferCors: deferViewCors }
2246
2354
  );
2247
2355
  if (viewAssetsHandler !== void 0) {
2248
- routes.push({
2249
- match: (request) => request.method === "GET" || request.method === "HEAD" ? new URL(request.url).pathname.startsWith(
2250
- `${nestedBasePath}/_mcp-use/views/`
2251
- ) : false,
2252
- handler: viewAssetsHandler
2253
- });
2356
+ this.app.on(
2357
+ ["GET", "HEAD"],
2358
+ `${nestedBasePath}/_mcp-use/views/*`,
2359
+ (context) => viewAssetsHandler(context.req.raw)
2360
+ );
2254
2361
  }
2255
2362
  }
2256
- routes.push({
2257
- match: (request) => matchesPath(request, basePath),
2258
- handler: endpointHandler
2259
- });
2260
- const terminal = routeFetch(routes);
2261
- this.#fetchHandler = composeFetch(terminal, ...middlewares);
2363
+ this.app.all(basePath, (context) => endpointHandler(context.req.raw));
2364
+ httpApp.route("/", this.app);
2365
+ this.#httpApp = httpApp;
2366
+ this.#fetchHandler = async (request) => httpApp.fetch(request);
2262
2367
  this.#handler = handler;
2263
2368
  this.#hostValidated = hosts !== void 0;
2264
- } else if (bus !== void 0 && this.#handler.bus !== bus) {
2265
- throw new Error(
2266
- "Cannot change the MCP event bus after the server has started."
2267
- );
2268
2369
  } else if (mode === "listen" && !this.#hostValidated && this.#validationPolicy("listen", listenHost).hosts !== void 0) {
2269
2370
  throw new Error(
2270
- "Cannot listen() on a localhost bind after getHandler(): the app is already mounted without Host validation (getHandler() expects a platform edge in front). Call listen() first, or set allowedHosts."
2371
+ "Cannot listen() on a localhost bind after server.fetch mounted the app without Host validation (server.fetch expects a platform edge in front). Call listen() first, or set allowedHosts."
2271
2372
  );
2272
2373
  }
2273
2374
  return { fetch: this.#fetchHandler, handler: this.#handler };
@@ -2382,16 +2483,16 @@ var MCPServer = class _MCPServer {
2382
2483
  return server;
2383
2484
  }
2384
2485
  #createMiddlewareContext(method, params, ctx) {
2385
- return {
2486
+ const requestContext = toRequestContext(ctx);
2487
+ return Object.assign(requestContext, {
2386
2488
  method,
2387
2489
  params,
2388
- ...ctx.http?.req !== void 0 && { request: ctx.http.req },
2389
2490
  ...ctx.sessionId !== void 0 && {
2390
2491
  session: { sessionId: ctx.sessionId }
2391
2492
  },
2392
2493
  ...ctx.http?.authInfo !== void 0 && { auth: ctx.http.authInfo },
2393
2494
  state: /* @__PURE__ */ new Map()
2394
- };
2495
+ });
2395
2496
  }
2396
2497
  #runMcpHook(method, ctx, innerFn) {
2397
2498
  return runMcpOperation(
@@ -2554,7 +2655,7 @@ var MCPServer = class _MCPServer {
2554
2655
  ...metaOptions.hmrWs === true ? { hmrWs: true } : {}
2555
2656
  } : metaOptions.hmrWs === true ? { hmrWs: true } : {};
2556
2657
  const assetsBase = req !== void 0 ? resolveAssetsBase(req) : metaOptions.request !== void 0 ? resolveAssetsBase(metaOptions.request) : "";
2557
- const html = synthesizeViewDocument(
2658
+ const html2 = synthesizeViewDocument(
2558
2659
  entry,
2559
2660
  assetsBase,
2560
2661
  basePath,
@@ -2565,7 +2666,7 @@ var MCPServer = class _MCPServer {
2565
2666
  {
2566
2667
  uri: readUri.href,
2567
2668
  mimeType: resourceConfig.mimeType,
2568
- text: html,
2669
+ text: html2,
2569
2670
  _meta: buildResourceUiMeta(authorFacts, readOptions)
2570
2671
  }
2571
2672
  ]
@@ -2601,12 +2702,11 @@ var MCPServer = class _MCPServer {
2601
2702
  },
2602
2703
  ctx
2603
2704
  );
2604
- const innerFn = async () => callback(uri, this.#toRequestContext(ctx));
2605
- return await this.#runMcpHook(
2606
- "resources/read",
2607
- mwCtx,
2608
- innerFn
2705
+ const innerFn = async () => toResourceResult(
2706
+ await callback(uri, this.#toRequestContext(ctx)),
2707
+ uri.href
2609
2708
  );
2709
+ return await this.#runMcpHook("resources/read", mwCtx, innerFn);
2610
2710
  }
2611
2711
  );
2612
2712
  }
@@ -2642,16 +2742,15 @@ var MCPServer = class _MCPServer {
2642
2742
  },
2643
2743
  ctx
2644
2744
  );
2645
- const innerFn = async () => callback(
2646
- uri,
2647
- variables,
2648
- this.#toRequestContext(ctx)
2649
- );
2650
- return await this.#runMcpHook(
2651
- "resources/read",
2652
- mwCtx,
2653
- innerFn
2745
+ const innerFn = async () => toResourceResult(
2746
+ await callback(
2747
+ uri,
2748
+ variables,
2749
+ this.#toRequestContext(ctx)
2750
+ ),
2751
+ uri.href
2654
2752
  );
2753
+ return await this.#runMcpHook("resources/read", mwCtx, innerFn);
2655
2754
  }
2656
2755
  );
2657
2756
  }
@@ -2692,7 +2791,9 @@ var MCPServer = class _MCPServer {
2692
2791
  );
2693
2792
  const innerFn = async () => {
2694
2793
  const effectiveArgs = mwCtx.params.arguments ?? {};
2695
- return callback(effectiveArgs, this.#toRequestContext(ctx));
2794
+ return toPromptResult(
2795
+ await callback(effectiveArgs, this.#toRequestContext(ctx))
2796
+ );
2696
2797
  };
2697
2798
  return await this.#runMcpHook("prompts/get", mwCtx, innerFn);
2698
2799
  };
@@ -2727,9 +2828,186 @@ import {
2727
2828
  inputResponse as inputResponse2,
2728
2829
  isInputRequiredResult as isInputRequiredResult3
2729
2830
  } from "@modelcontextprotocol/server";
2831
+
2832
+ // src/response-helpers.ts
2833
+ function text(content) {
2834
+ return {
2835
+ content: [{ type: "text", text: content }],
2836
+ _meta: { mimeType: "text/plain" }
2837
+ };
2838
+ }
2839
+ function markdown(content) {
2840
+ return {
2841
+ content: [{ type: "text", text: content }],
2842
+ _meta: { mimeType: "text/markdown" }
2843
+ };
2844
+ }
2845
+ function html(content) {
2846
+ return {
2847
+ content: [{ type: "text", text: content }],
2848
+ _meta: { mimeType: "text/html" }
2849
+ };
2850
+ }
2851
+ function xml(content) {
2852
+ return {
2853
+ content: [{ type: "text", text: content }],
2854
+ _meta: { mimeType: "text/xml" }
2855
+ };
2856
+ }
2857
+ function css(content) {
2858
+ return {
2859
+ content: [{ type: "text", text: content }],
2860
+ _meta: { mimeType: "text/css" }
2861
+ };
2862
+ }
2863
+ function javascript(content) {
2864
+ return {
2865
+ content: [{ type: "text", text: content }],
2866
+ _meta: { mimeType: "text/javascript" }
2867
+ };
2868
+ }
2869
+ function image(data, mimeType = "image/png") {
2870
+ return {
2871
+ content: [{ type: "image", data, mimeType }],
2872
+ _meta: { mimeType, isImage: true }
2873
+ };
2874
+ }
2875
+ function audio(data, mimeType = "audio/wav") {
2876
+ return {
2877
+ content: [{ type: "audio", data, mimeType }],
2878
+ _meta: { mimeType, isAudio: true }
2879
+ };
2880
+ }
2881
+ function binary(base64Data, mimeType) {
2882
+ return {
2883
+ content: [{ type: "text", text: base64Data }],
2884
+ _meta: { mimeType, isBinary: true }
2885
+ };
2886
+ }
2887
+ function resource(uri, mimeTypeOrContent, text2) {
2888
+ if (typeof mimeTypeOrContent === "object" && mimeTypeOrContent !== null && "content" in mimeTypeOrContent) {
2889
+ const contentResult = mimeTypeOrContent;
2890
+ let extractedText;
2891
+ let extractedMimeType;
2892
+ if (contentResult._meta && typeof contentResult._meta === "object") {
2893
+ const meta = contentResult._meta;
2894
+ if (typeof meta.mimeType === "string") {
2895
+ extractedMimeType = meta.mimeType;
2896
+ }
2897
+ }
2898
+ const first = contentResult.content?.[0];
2899
+ if (first?.type === "text" && "text" in first) {
2900
+ extractedText = first.text;
2901
+ }
2902
+ return {
2903
+ content: [
2904
+ {
2905
+ type: "resource",
2906
+ resource: {
2907
+ uri,
2908
+ ...extractedMimeType !== void 0 && {
2909
+ mimeType: extractedMimeType
2910
+ },
2911
+ text: extractedText ?? ""
2912
+ }
2913
+ }
2914
+ ]
2915
+ };
2916
+ }
2917
+ const mimeType = mimeTypeOrContent;
2918
+ return {
2919
+ content: [
2920
+ {
2921
+ type: "resource",
2922
+ resource: {
2923
+ uri,
2924
+ ...mimeType !== void 0 && mimeType !== "" && { mimeType },
2925
+ text: text2 ?? ""
2926
+ }
2927
+ }
2928
+ ]
2929
+ };
2930
+ }
2931
+ function error(message) {
2932
+ return {
2933
+ isError: true,
2934
+ content: [{ type: "text", text: message }]
2935
+ };
2936
+ }
2937
+ function object(data) {
2938
+ if (Array.isArray(data)) {
2939
+ return array(data);
2940
+ }
2941
+ return {
2942
+ content: [
2943
+ {
2944
+ type: "text",
2945
+ text: JSON.stringify(data, null, 2)
2946
+ }
2947
+ ],
2948
+ structuredContent: data,
2949
+ _meta: { mimeType: "application/json" }
2950
+ };
2951
+ }
2952
+ function array(data) {
2953
+ return {
2954
+ content: [
2955
+ {
2956
+ type: "text",
2957
+ text: JSON.stringify(data, null, 2)
2958
+ }
2959
+ ],
2960
+ structuredContent: data
2961
+ };
2962
+ }
2963
+ function widget(config) {
2964
+ const props = config.props ?? config.data ?? {};
2965
+ const { output, message, metadata } = config;
2966
+ const finalContent = message ? [{ type: "text", text: message }] : Array.isArray(output?.content) && output.content.length > 0 ? output.content : [{ type: "text", text: "" }];
2967
+ const result = {
2968
+ content: finalContent
2969
+ };
2970
+ if (metadata !== void 0 && Object.keys(metadata).length > 0) {
2971
+ result._meta = metadata;
2972
+ }
2973
+ if (output?.structuredContent !== void 0) {
2974
+ result.structuredContent = output.structuredContent;
2975
+ } else if (Object.keys(props).length > 0) {
2976
+ result.structuredContent = props;
2977
+ }
2978
+ return result;
2979
+ }
2980
+ function mix(...results) {
2981
+ const withStructured = results.filter(
2982
+ (result) => result.structuredContent !== void 0
2983
+ );
2984
+ const structuredContent = withStructured.length > 0 ? withStructured.map((result) => result.structuredContent).reduce(
2985
+ (acc, value) => ({
2986
+ ...acc,
2987
+ ...typeof value === "object" && value !== null ? value : {}
2988
+ }),
2989
+ {}
2990
+ ) : void 0;
2991
+ const withMeta = results.filter((result) => result._meta !== void 0);
2992
+ const _meta = withMeta.length > 0 ? withMeta.map((result) => result._meta).reduce(
2993
+ (acc, value) => ({
2994
+ ...acc,
2995
+ ...value !== void 0 ? value : {}
2996
+ }),
2997
+ {}
2998
+ ) : void 0;
2999
+ return {
3000
+ content: results.flatMap((result) => result.content),
3001
+ ...structuredContent !== void 0 && Object.keys(structuredContent).length > 0 && { structuredContent },
3002
+ ..._meta !== void 0 && Object.keys(_meta).length > 0 && { _meta }
3003
+ };
3004
+ }
2730
3005
  export {
2731
3006
  MCPServer,
2732
3007
  acceptedContent,
3008
+ array,
3009
+ audio,
3010
+ binary,
2733
3011
  completable,
2734
3012
  composeFetch,
2735
3013
  composeMiddleware,
@@ -2737,19 +3015,29 @@ export {
2737
3015
  createMcpMiddlewareEntry,
2738
3016
  createMcpMount,
2739
3017
  createRequestStateCodec,
3018
+ css,
3019
+ error,
2740
3020
  getRequestBag,
2741
3021
  hostValidationMiddleware,
3022
+ html,
3023
+ image,
2742
3024
  inputRequired2 as inputRequired,
2743
3025
  inputResponse2 as inputResponse,
2744
3026
  isInputRequiredResult3 as isInputRequiredResult,
3027
+ javascript,
2745
3028
  jsonBodyMiddleware,
3029
+ markdown,
2746
3030
  matchesPath,
2747
3031
  matchesPathPrefix,
2748
3032
  matchesPattern,
3033
+ mix,
3034
+ object,
2749
3035
  originValidationMiddleware,
2750
3036
  pathnameOf,
2751
3037
  registerViews,
2752
3038
  requestLogger,
2753
- routeFetch,
2754
- toFrameworkHandler
3039
+ resource,
3040
+ text,
3041
+ widget,
3042
+ xml
2755
3043
  };