@12-apps/mcp 3.2.0 → 3.2.1
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/chunk-7QVYU63E.js +7 -0
- package/dist/chunk-7QVYU63E.js.map +1 -0
- package/dist/chunk-FYEVBTDU.js +162 -0
- package/dist/chunk-FYEVBTDU.js.map +1 -0
- package/dist/chunk-HAZOPC6U.js +229 -0
- package/dist/chunk-HAZOPC6U.js.map +1 -0
- package/dist/chunk-UIILEGAC.js +1247 -0
- package/dist/chunk-UIILEGAC.js.map +1 -0
- package/dist/chunk-WJJNKKNS.js +63 -0
- package/dist/chunk-WJJNKKNS.js.map +1 -0
- package/dist/coverage-gate/index.d.ts +129 -0
- package/dist/coverage-gate/index.js +163 -0
- package/dist/coverage-gate/index.js.map +1 -0
- package/dist/create-api-mcp-oauth-CwVXKK-A.d.ts +647 -0
- package/dist/generate/index.d.ts +91 -0
- package/dist/generate/index.js +101 -0
- package/dist/generate/index.js.map +1 -0
- package/dist/generate-Dx3cK8th.d.ts +184 -0
- package/dist/guide-DV5MQbCg.d.ts +135 -0
- package/dist/hono/index.d.ts +28 -0
- package/dist/hono/index.js +25 -0
- package/dist/hono/index.js.map +1 -0
- package/dist/index.d.ts +382 -0
- package/dist/index.js +331 -0
- package/dist/index.js.map +1 -0
- package/dist/oauth/index.d.ts +446 -0
- package/dist/oauth/index.js +279 -0
- package/dist/oauth/index.js.map +1 -0
- package/dist/react/index.d.ts +239 -0
- package/dist/react/index.js +1183 -0
- package/dist/react/index.js.map +1 -0
- package/package.json +31 -10
- package/prisma/migrations/20260812150000_add_mcp_oauth_tables/migration.sql +6 -6
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { T as ToolManifest, O as OpenApiDocument } from '../generate-Dx3cK8th.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `@12-apps/mcp/generate` — the `mcp:generate` / `mcp:check` gate (12-23), moved
|
|
5
|
+
* out of the origin host's `apps/web/scripts/mcp/generate.ts` so a host's own script is
|
|
6
|
+
* a one-line call and `12-apps/ci`'s `mcp-contract.yml`, which shells out to the
|
|
7
|
+
* consumer's `mcp:check` package script, keeps working unchanged.
|
|
8
|
+
*
|
|
9
|
+
* It renders the committed surface artifacts from the host's OpenAPI document:
|
|
10
|
+
*
|
|
11
|
+
* openapi.json — the document itself, canonicalized
|
|
12
|
+
* manifest.json — the MCP tool manifest generated from it
|
|
13
|
+
* surface-lock.json — which surface the current version stands for
|
|
14
|
+
*
|
|
15
|
+
* With `check: true` it regenerates IN MEMORY and fails on any drift — the same
|
|
16
|
+
* command CI runs, so a forgotten regeneration is a red build rather than a tool
|
|
17
|
+
* list that silently disagrees with the endpoints.
|
|
18
|
+
*
|
|
19
|
+
* It ALSO refuses, in both modes, to emit a tool surface that changed while the
|
|
20
|
+
* advertised VERSION did not. That version is the only signal a connected host has
|
|
21
|
+
* that `tools/list` is worth re-reading, so a shipped tool behind an unmoved
|
|
22
|
+
* version is invisible to every client that already cached it — and "remember to
|
|
23
|
+
* bump it" as a comment is not a rule (see `server/surface-lock.ts`).
|
|
24
|
+
*/
|
|
25
|
+
/** One extra artifact a host renders from the same manifest, e.g. a store submission. */
|
|
26
|
+
interface McpExtraArtifact {
|
|
27
|
+
/** Absolute path of the committed file. */
|
|
28
|
+
path: string;
|
|
29
|
+
/** Rendered text, INCLUDING its trailing newline (compared byte for byte). */
|
|
30
|
+
render: (manifest: ToolManifest) => string;
|
|
31
|
+
}
|
|
32
|
+
interface McpGenerateOptions {
|
|
33
|
+
/**
|
|
34
|
+
* The host's OpenAPI document, or a thunk producing it. A thunk is the useful
|
|
35
|
+
* form: building it usually evaluates a Zod registry, and `--check` should pay
|
|
36
|
+
* that cost once, when it runs.
|
|
37
|
+
*/
|
|
38
|
+
document: OpenApiDocument | (() => OpenApiDocument);
|
|
39
|
+
/**
|
|
40
|
+
* The advertised surface version — the number a client is handed on `initialize`
|
|
41
|
+
* and caches `tools/list` against.
|
|
42
|
+
*/
|
|
43
|
+
version: number;
|
|
44
|
+
/** Human label for the spec the tools were generated from. */
|
|
45
|
+
source: string;
|
|
46
|
+
/**
|
|
47
|
+
* Where the host's version constant lives, repo-relative — quoted verbatim in
|
|
48
|
+
* the surface-lock failure, so the fix is a path and a value rather than a hunt.
|
|
49
|
+
*/
|
|
50
|
+
versionLocation: string;
|
|
51
|
+
/** The constant's name, if the host does not call it `MCP_SURFACE_VERSION`. */
|
|
52
|
+
versionName?: string;
|
|
53
|
+
/** Where the three artifacts are committed. */
|
|
54
|
+
outputs: {
|
|
55
|
+
openapi: string;
|
|
56
|
+
manifest: string;
|
|
57
|
+
surfaceLock: string;
|
|
58
|
+
};
|
|
59
|
+
/** Anything else the host commits from the same manifest. */
|
|
60
|
+
extraArtifacts?: readonly McpExtraArtifact[];
|
|
61
|
+
}
|
|
62
|
+
/** The rendered text of every artifact, keyed by its committed path. */
|
|
63
|
+
type RenderedArtifacts = Map<string, string>;
|
|
64
|
+
interface McpGenerateResult {
|
|
65
|
+
artifacts: RenderedArtifacts;
|
|
66
|
+
/** Non-null when the surface moved without a version bump — the message to print. */
|
|
67
|
+
surfaceProblem: string | null;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Render every artifact from the document. Pure: nothing is written and nothing is
|
|
71
|
+
* compared, so a caller can diff, print or discard the result.
|
|
72
|
+
*/
|
|
73
|
+
declare function renderMcpArtifacts(options: McpGenerateOptions): McpGenerateResult;
|
|
74
|
+
/** Every artifact whose committed text differs from a fresh render. */
|
|
75
|
+
declare function mcpArtifactDrift(artifacts: RenderedArtifacts): string[];
|
|
76
|
+
/** Write every artifact, creating directories as needed. */
|
|
77
|
+
declare function writeMcpArtifacts(artifacts: RenderedArtifacts): void;
|
|
78
|
+
interface McpGenerateCliOptions extends McpGenerateOptions {
|
|
79
|
+
/** `true` for `mcp:check` (verify only), `false` for `mcp:generate` (write). */
|
|
80
|
+
check: boolean;
|
|
81
|
+
/** The command to suggest on drift. Default: `pnpm mcp:generate`. */
|
|
82
|
+
regenerateCommand?: string;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The CLI face: render, then either verify or write, printing the verdict and
|
|
86
|
+
* exiting non-zero on any failure. A host's `scripts/mcp/generate.ts` becomes an
|
|
87
|
+
* import, its document builder, and one call.
|
|
88
|
+
*/
|
|
89
|
+
declare function mcpGenerateCli(options: McpGenerateCliOptions): void;
|
|
90
|
+
|
|
91
|
+
export { type McpExtraArtifact, type McpGenerateCliOptions, type McpGenerateOptions, type McpGenerateResult, type RenderedArtifacts, mcpArtifactDrift, mcpGenerateCli, renderMcpArtifacts, writeMcpArtifacts };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildManifest,
|
|
3
|
+
generateTools,
|
|
4
|
+
serializeManifest,
|
|
5
|
+
serializeSurfaceLock,
|
|
6
|
+
surfaceDigest,
|
|
7
|
+
surfaceLockProblem
|
|
8
|
+
} from "../chunk-HAZOPC6U.js";
|
|
9
|
+
import {
|
|
10
|
+
__name
|
|
11
|
+
} from "../chunk-7QVYU63E.js";
|
|
12
|
+
|
|
13
|
+
// src/generate/index.ts
|
|
14
|
+
import { mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
15
|
+
import { dirname } from "path";
|
|
16
|
+
function readOrEmpty(path) {
|
|
17
|
+
try {
|
|
18
|
+
return readFileSync(path, "utf8");
|
|
19
|
+
} catch {
|
|
20
|
+
return "";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
__name(readOrEmpty, "readOrEmpty");
|
|
24
|
+
function readSurfaceLock(path) {
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
27
|
+
} catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
__name(readSurfaceLock, "readSurfaceLock");
|
|
32
|
+
function renderMcpArtifacts(options) {
|
|
33
|
+
const document = typeof options.document === "function" ? options.document() : options.document;
|
|
34
|
+
const tools = generateTools(document);
|
|
35
|
+
const digest = surfaceDigest(tools, options.source);
|
|
36
|
+
const surfaceProblem = surfaceLockProblem({
|
|
37
|
+
previous: readSurfaceLock(options.outputs.surfaceLock),
|
|
38
|
+
version: options.version,
|
|
39
|
+
digest,
|
|
40
|
+
versionLocation: options.versionLocation,
|
|
41
|
+
...options.versionName ? { versionName: options.versionName } : {}
|
|
42
|
+
});
|
|
43
|
+
const manifestValue = buildManifest(tools, {
|
|
44
|
+
version: options.version,
|
|
45
|
+
source: options.source
|
|
46
|
+
});
|
|
47
|
+
const artifacts = /* @__PURE__ */ new Map([
|
|
48
|
+
[options.outputs.openapi, `${JSON.stringify(document, null, 2)}
|
|
49
|
+
`],
|
|
50
|
+
[options.outputs.manifest, serializeManifest(manifestValue)],
|
|
51
|
+
[
|
|
52
|
+
options.outputs.surfaceLock,
|
|
53
|
+
serializeSurfaceLock({ version: options.version, digest })
|
|
54
|
+
]
|
|
55
|
+
]);
|
|
56
|
+
for (const extra of options.extraArtifacts ?? []) {
|
|
57
|
+
artifacts.set(extra.path, extra.render(manifestValue));
|
|
58
|
+
}
|
|
59
|
+
return { artifacts, surfaceProblem };
|
|
60
|
+
}
|
|
61
|
+
__name(renderMcpArtifacts, "renderMcpArtifacts");
|
|
62
|
+
function mcpArtifactDrift(artifacts) {
|
|
63
|
+
return [...artifacts.entries()].filter(([path, rendered]) => readOrEmpty(path) !== rendered).map(([path]) => path);
|
|
64
|
+
}
|
|
65
|
+
__name(mcpArtifactDrift, "mcpArtifactDrift");
|
|
66
|
+
function writeMcpArtifacts(artifacts) {
|
|
67
|
+
for (const [path, contents] of artifacts) {
|
|
68
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
69
|
+
writeFileSync(path, contents);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
__name(writeMcpArtifacts, "writeMcpArtifacts");
|
|
73
|
+
function mcpGenerateCli(options) {
|
|
74
|
+
const { artifacts, surfaceProblem } = renderMcpArtifacts(options);
|
|
75
|
+
if (surfaceProblem) {
|
|
76
|
+
console.error(`[mcp:surface] ${surfaceProblem}`);
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
if (options.check) {
|
|
80
|
+
const drift = mcpArtifactDrift(artifacts);
|
|
81
|
+
if (drift.length > 0) {
|
|
82
|
+
console.error(
|
|
83
|
+
`[mcp:check] drift in: ${drift.join(", ")}.
|
|
84
|
+
Run \`${options.regenerateCommand ?? "pnpm mcp:generate"}\` and commit the result.`
|
|
85
|
+
);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
console.log("[mcp:check] MCP surface is in sync with the OpenAPI registry.");
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
writeMcpArtifacts(artifacts);
|
|
92
|
+
console.log(`[mcp:generate] wrote ${[...artifacts.keys()].join(", ")}`);
|
|
93
|
+
}
|
|
94
|
+
__name(mcpGenerateCli, "mcpGenerateCli");
|
|
95
|
+
export {
|
|
96
|
+
mcpArtifactDrift,
|
|
97
|
+
mcpGenerateCli,
|
|
98
|
+
renderMcpArtifacts,
|
|
99
|
+
writeMcpArtifacts
|
|
100
|
+
};
|
|
101
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/generate/index.ts"],"sourcesContent":["import { mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\n\nimport { generateTools, type OpenApiDocument } from \"../openapi/generate\";\nimport { buildManifest, serializeManifest } from \"../server/manifest\";\nimport {\n serializeSurfaceLock,\n surfaceDigest,\n surfaceLockProblem,\n type SurfaceLock,\n} from \"../server/surface-lock\";\nimport type { ToolManifest } from \"../types\";\n\n/**\n * `@12-apps/mcp/generate` — the `mcp:generate` / `mcp:check` gate (12-23), moved\n * out of the origin host's `apps/web/scripts/mcp/generate.ts` so a host's own script is\n * a one-line call and `12-apps/ci`'s `mcp-contract.yml`, which shells out to the\n * consumer's `mcp:check` package script, keeps working unchanged.\n *\n * It renders the committed surface artifacts from the host's OpenAPI document:\n *\n * openapi.json — the document itself, canonicalized\n * manifest.json — the MCP tool manifest generated from it\n * surface-lock.json — which surface the current version stands for\n *\n * With `check: true` it regenerates IN MEMORY and fails on any drift — the same\n * command CI runs, so a forgotten regeneration is a red build rather than a tool\n * list that silently disagrees with the endpoints.\n *\n * It ALSO refuses, in both modes, to emit a tool surface that changed while the\n * advertised VERSION did not. That version is the only signal a connected host has\n * that `tools/list` is worth re-reading, so a shipped tool behind an unmoved\n * version is invisible to every client that already cached it — and \"remember to\n * bump it\" as a comment is not a rule (see `server/surface-lock.ts`).\n */\n\n/** One extra artifact a host renders from the same manifest, e.g. a store submission. */\nexport interface McpExtraArtifact {\n /** Absolute path of the committed file. */\n path: string;\n /** Rendered text, INCLUDING its trailing newline (compared byte for byte). */\n render: (manifest: ToolManifest) => string;\n}\n\nexport interface McpGenerateOptions {\n /**\n * The host's OpenAPI document, or a thunk producing it. A thunk is the useful\n * form: building it usually evaluates a Zod registry, and `--check` should pay\n * that cost once, when it runs.\n */\n document: OpenApiDocument | (() => OpenApiDocument);\n /**\n * The advertised surface version — the number a client is handed on `initialize`\n * and caches `tools/list` against.\n */\n version: number;\n /** Human label for the spec the tools were generated from. */\n source: string;\n /**\n * Where the host's version constant lives, repo-relative — quoted verbatim in\n * the surface-lock failure, so the fix is a path and a value rather than a hunt.\n */\n versionLocation: string;\n /** The constant's name, if the host does not call it `MCP_SURFACE_VERSION`. */\n versionName?: string;\n /** Where the three artifacts are committed. */\n outputs: {\n openapi: string;\n manifest: string;\n surfaceLock: string;\n };\n /** Anything else the host commits from the same manifest. */\n extraArtifacts?: readonly McpExtraArtifact[];\n}\n\n/** The rendered text of every artifact, keyed by its committed path. */\nexport type RenderedArtifacts = Map<string, string>;\n\nexport interface McpGenerateResult {\n artifacts: RenderedArtifacts;\n /** Non-null when the surface moved without a version bump — the message to print. */\n surfaceProblem: string | null;\n}\n\nfunction readOrEmpty(path: string): string {\n try {\n return readFileSync(path, \"utf8\");\n } catch {\n return \"\";\n }\n}\n\nfunction readSurfaceLock(path: string): SurfaceLock | null {\n try {\n return JSON.parse(readFileSync(path, \"utf8\")) as SurfaceLock;\n } catch {\n // No lock committed yet — there is nothing to contradict.\n return null;\n }\n}\n\n/**\n * Render every artifact from the document. Pure: nothing is written and nothing is\n * compared, so a caller can diff, print or discard the result.\n */\nexport function renderMcpArtifacts(options: McpGenerateOptions): McpGenerateResult {\n const document =\n typeof options.document === \"function\" ? options.document() : options.document;\n const tools = generateTools(document);\n\n // Before anything is written or compared: does this version still stand for this\n // surface? The digest is of what `tools/list` would actually return, which is\n // neither over- nor under-sensitive the way a paths filter on the registry's\n // source tree is in both directions.\n const digest = surfaceDigest(tools, options.source);\n const surfaceProblem = surfaceLockProblem({\n previous: readSurfaceLock(options.outputs.surfaceLock),\n version: options.version,\n digest,\n versionLocation: options.versionLocation,\n ...(options.versionName ? { versionName: options.versionName } : {}),\n });\n\n const manifestValue = buildManifest(tools, {\n version: options.version,\n source: options.source,\n });\n\n const artifacts: RenderedArtifacts = new Map([\n [options.outputs.openapi, `${JSON.stringify(document, null, 2)}\\n`],\n [options.outputs.manifest, serializeManifest(manifestValue)],\n [\n options.outputs.surfaceLock,\n serializeSurfaceLock({ version: options.version, digest }),\n ],\n ]);\n for (const extra of options.extraArtifacts ?? []) {\n artifacts.set(extra.path, extra.render(manifestValue));\n }\n\n return { artifacts, surfaceProblem };\n}\n\n/** Every artifact whose committed text differs from a fresh render. */\nexport function mcpArtifactDrift(artifacts: RenderedArtifacts): string[] {\n return [...artifacts.entries()]\n .filter(([path, rendered]) => readOrEmpty(path) !== rendered)\n .map(([path]) => path);\n}\n\n/** Write every artifact, creating directories as needed. */\nexport function writeMcpArtifacts(artifacts: RenderedArtifacts): void {\n for (const [path, contents] of artifacts) {\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, contents);\n }\n}\n\nexport interface McpGenerateCliOptions extends McpGenerateOptions {\n /** `true` for `mcp:check` (verify only), `false` for `mcp:generate` (write). */\n check: boolean;\n /** The command to suggest on drift. Default: `pnpm mcp:generate`. */\n regenerateCommand?: string;\n}\n\n/**\n * The CLI face: render, then either verify or write, printing the verdict and\n * exiting non-zero on any failure. A host's `scripts/mcp/generate.ts` becomes an\n * import, its document builder, and one call.\n */\nexport function mcpGenerateCli(options: McpGenerateCliOptions): void {\n const { artifacts, surfaceProblem } = renderMcpArtifacts(options);\n\n if (surfaceProblem) {\n // Exits rather than throws so the message IS the whole output — it names the\n // number to change and where, which is the entire point of failing here\n // instead of leaving it to review.\n console.error(`[mcp:surface] ${surfaceProblem}`);\n process.exit(1);\n }\n\n if (options.check) {\n const drift = mcpArtifactDrift(artifacts);\n if (drift.length > 0) {\n console.error(\n `[mcp:check] drift in: ${drift.join(\", \")}.\\n` +\n `Run \\`${options.regenerateCommand ?? \"pnpm mcp:generate\"}\\` and commit the result.`,\n );\n process.exit(1);\n }\n console.log(\"[mcp:check] MCP surface is in sync with the OpenAPI registry.\");\n return;\n }\n\n writeMcpArtifacts(artifacts);\n console.log(`[mcp:generate] wrote ${[...artifacts.keys()].join(\", \")}`);\n}\n"],"mappings":";;;;;;;;;;;;;AAAA,SAAS,WAAW,cAAc,qBAAqB;AACvD,SAAS,eAAe;AAmFxB,SAAS,YAAY,MAAsB;AACzC,MAAI;AACF,WAAO,aAAa,MAAM,MAAM;AAAA,EAClC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AANS;AAQT,SAAS,gBAAgB,MAAkC;AACzD,MAAI;AACF,WAAO,KAAK,MAAM,aAAa,MAAM,MAAM,CAAC;AAAA,EAC9C,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;AAPS;AAaF,SAAS,mBAAmB,SAAgD;AACjF,QAAM,WACJ,OAAO,QAAQ,aAAa,aAAa,QAAQ,SAAS,IAAI,QAAQ;AACxE,QAAM,QAAQ,cAAc,QAAQ;AAMpC,QAAM,SAAS,cAAc,OAAO,QAAQ,MAAM;AAClD,QAAM,iBAAiB,mBAAmB;AAAA,IACxC,UAAU,gBAAgB,QAAQ,QAAQ,WAAW;AAAA,IACrD,SAAS,QAAQ;AAAA,IACjB;AAAA,IACA,iBAAiB,QAAQ;AAAA,IACzB,GAAI,QAAQ,cAAc,EAAE,aAAa,QAAQ,YAAY,IAAI,CAAC;AAAA,EACpE,CAAC;AAED,QAAM,gBAAgB,cAAc,OAAO;AAAA,IACzC,SAAS,QAAQ;AAAA,IACjB,QAAQ,QAAQ;AAAA,EAClB,CAAC;AAED,QAAM,YAA+B,oBAAI,IAAI;AAAA,IAC3C,CAAC,QAAQ,QAAQ,SAAS,GAAG,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,IAClE,CAAC,QAAQ,QAAQ,UAAU,kBAAkB,aAAa,CAAC;AAAA,IAC3D;AAAA,MACE,QAAQ,QAAQ;AAAA,MAChB,qBAAqB,EAAE,SAAS,QAAQ,SAAS,OAAO,CAAC;AAAA,IAC3D;AAAA,EACF,CAAC;AACD,aAAW,SAAS,QAAQ,kBAAkB,CAAC,GAAG;AAChD,cAAU,IAAI,MAAM,MAAM,MAAM,OAAO,aAAa,CAAC;AAAA,EACvD;AAEA,SAAO,EAAE,WAAW,eAAe;AACrC;AApCgB;AAuCT,SAAS,iBAAiB,WAAwC;AACvE,SAAO,CAAC,GAAG,UAAU,QAAQ,CAAC,EAC3B,OAAO,CAAC,CAAC,MAAM,QAAQ,MAAM,YAAY,IAAI,MAAM,QAAQ,EAC3D,IAAI,CAAC,CAAC,IAAI,MAAM,IAAI;AACzB;AAJgB;AAOT,SAAS,kBAAkB,WAAoC;AACpE,aAAW,CAAC,MAAM,QAAQ,KAAK,WAAW;AACxC,cAAU,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC5C,kBAAc,MAAM,QAAQ;AAAA,EAC9B;AACF;AALgB;AAmBT,SAAS,eAAe,SAAsC;AACnE,QAAM,EAAE,WAAW,eAAe,IAAI,mBAAmB,OAAO;AAEhE,MAAI,gBAAgB;AAIlB,YAAQ,MAAM,iBAAiB,cAAc,EAAE;AAC/C,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,QAAQ,OAAO;AACjB,UAAM,QAAQ,iBAAiB,SAAS;AACxC,QAAI,MAAM,SAAS,GAAG;AACpB,cAAQ;AAAA,QACN,yBAAyB,MAAM,KAAK,IAAI,CAAC;AAAA,QAC9B,QAAQ,qBAAqB,mBAAmB;AAAA,MAC7D;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,YAAQ,IAAI,+DAA+D;AAC3E;AAAA,EACF;AAEA,oBAAkB,SAAS;AAC3B,UAAQ,IAAI,wBAAwB,CAAC,GAAG,UAAU,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE;AACxE;AA1BgB;","names":[]}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core types for the app-agnostic MCP layer.
|
|
3
|
+
*
|
|
4
|
+
* The design in one sentence: generate one MCP tool per OpenAPI operation, and
|
|
5
|
+
* dispatch each tool call by proxying to the real HTTP endpoint carrying the
|
|
6
|
+
* caller's bearer token — so an agent gets exactly the user's permissions and
|
|
7
|
+
* authorization stays entirely in the endpoints (never re-implemented here).
|
|
8
|
+
*
|
|
9
|
+
* This package is deliberately free of any app/domain specifics and of the MCP
|
|
10
|
+
* transport SDK: it turns a spec into tools and a tool call into an HTTP request.
|
|
11
|
+
* The consuming app supplies the OpenAPI document, the base URL, and an
|
|
12
|
+
* {@link AuthResolver}; it binds {@link ToolRegistry} to the MCP transport.
|
|
13
|
+
*/
|
|
14
|
+
/** A JSON Schema object (draft 2020-12). We treat schemas opaquely and forward them. */
|
|
15
|
+
type JsonSchema = Record<string, unknown>;
|
|
16
|
+
/**
|
|
17
|
+
* MCP tool-behavior annotations used by clients for review and confirmation.
|
|
18
|
+
*
|
|
19
|
+
* Every value is required intentionally. ChatGPT App review treats a missing
|
|
20
|
+
* hint as a blocker, and an implicit protocol default is not enough evidence
|
|
21
|
+
* that a tool's behavior was audited. The Anthropic connector directory
|
|
22
|
+
* additionally requires a human-readable `title` on every tool, and derives
|
|
23
|
+
* auto-permissions from `readOnlyHint`/`destructiveHint`.
|
|
24
|
+
*/
|
|
25
|
+
interface ToolAnnotations {
|
|
26
|
+
/** Human-readable tool label (required by the Anthropic connector review). */
|
|
27
|
+
title: string;
|
|
28
|
+
readOnlyHint: boolean;
|
|
29
|
+
openWorldHint: boolean;
|
|
30
|
+
destructiveHint: boolean;
|
|
31
|
+
}
|
|
32
|
+
/** Where an operation parameter is carried in the HTTP request. */
|
|
33
|
+
type ParameterLocation = "path" | "query" | "header";
|
|
34
|
+
/** One OpenAPI operation parameter, retained so the dispatcher can route args. */
|
|
35
|
+
interface ToolParameter {
|
|
36
|
+
name: string;
|
|
37
|
+
in: ParameterLocation;
|
|
38
|
+
required: boolean;
|
|
39
|
+
schema: JsonSchema;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* A single generated MCP tool: an agent-facing input schema plus everything the
|
|
43
|
+
* dispatcher needs to reconstruct the HTTP call. This is the unit that is both
|
|
44
|
+
* served to agents and committed to the drift manifest.
|
|
45
|
+
*/
|
|
46
|
+
interface GeneratedTool {
|
|
47
|
+
/** Stable tool id: the operationId, or a `method_path` slug when absent. */
|
|
48
|
+
name: string;
|
|
49
|
+
description: string;
|
|
50
|
+
/** Uppercase HTTP method, e.g. "GET", "POST". */
|
|
51
|
+
method: string;
|
|
52
|
+
/** OpenAPI path template, e.g. "/products/{id}". */
|
|
53
|
+
path: string;
|
|
54
|
+
/** Agent-facing input schema (params + flattened request-body properties). */
|
|
55
|
+
inputSchema: JsonSchema;
|
|
56
|
+
/** Documented success-response schema, when the spec provides one. */
|
|
57
|
+
outputSchema?: JsonSchema;
|
|
58
|
+
/** Explicit, behavior-audited MCP review hints. */
|
|
59
|
+
annotations: ToolAnnotations;
|
|
60
|
+
/**
|
|
61
|
+
* Dotted response paths stripped before the result reaches the agent.
|
|
62
|
+
*
|
|
63
|
+
* `outputSchema` is advertisement only — the dispatcher forwards the upstream
|
|
64
|
+
* body verbatim — so narrowing a schema alone would misdescribe what is
|
|
65
|
+
* actually sent. Redaction is what removes the value; the narrowed schema
|
|
66
|
+
* just keeps the advertisement honest. A segment that lands on an array is
|
|
67
|
+
* applied to every element.
|
|
68
|
+
*/
|
|
69
|
+
redactResponse?: readonly string[];
|
|
70
|
+
/** Path/query/header parameters, in declaration order. */
|
|
71
|
+
parameters: ToolParameter[];
|
|
72
|
+
/** Top-level property names sourced from the request body (routed to the body). */
|
|
73
|
+
bodyProps: string[];
|
|
74
|
+
/** True when the request body is not an object (sent verbatim as the payload). */
|
|
75
|
+
bodyIsWhole: boolean;
|
|
76
|
+
/** True for POST/PUT/PATCH/DELETE — a write. Consumers may gate these. */
|
|
77
|
+
mutating: boolean;
|
|
78
|
+
/** OpenAPI security requirement names referenced by the operation, if any. */
|
|
79
|
+
security: string[];
|
|
80
|
+
}
|
|
81
|
+
/** The committed source-of-truth artifact the drift gate (`mcp:check`) diffs. */
|
|
82
|
+
interface ToolManifest {
|
|
83
|
+
/** Bumped on any intentional shape change (mirrors the golden-catalog convention). */
|
|
84
|
+
version: number;
|
|
85
|
+
/** Human label for the spec the tools were generated from. */
|
|
86
|
+
source: string;
|
|
87
|
+
tools: GeneratedTool[];
|
|
88
|
+
}
|
|
89
|
+
/** Options controlling tool generation from an OpenAPI document. */
|
|
90
|
+
interface GenerateOptions {
|
|
91
|
+
/** Only include operations whose method is in this set (default: all). */
|
|
92
|
+
includeMethods?: readonly string[];
|
|
93
|
+
/** Drop operations tagged with any of these (e.g. "internal"). */
|
|
94
|
+
excludeTags?: readonly string[];
|
|
95
|
+
/** Predicate to include/exclude an operation by (method, path). */
|
|
96
|
+
filter?: (method: string, path: string) => boolean;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The caller's resolved authorization for a single request. The dispatcher only
|
|
100
|
+
* ever forwards `bearer` upstream; identity/permission checks happen at the
|
|
101
|
+
* endpoint. `subject`/`scopes` are surfaced for logging and tool-visibility
|
|
102
|
+
* decisions, not for authorization.
|
|
103
|
+
*/
|
|
104
|
+
interface RequestAuth {
|
|
105
|
+
/** The bearer token to forward to the upstream endpoint (verbatim). */
|
|
106
|
+
bearer: string;
|
|
107
|
+
/** Token subject (for logging only). */
|
|
108
|
+
subject?: string;
|
|
109
|
+
/** Granted scopes (for optional tool visibility filtering). */
|
|
110
|
+
scopes?: readonly string[];
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* App-supplied hook that turns an incoming request into {@link RequestAuth}, or
|
|
114
|
+
* `null` when unauthenticated. For the OAuth resource-server mode this validates
|
|
115
|
+
* the access token (signature/audience/scope) and returns the token to forward.
|
|
116
|
+
*/
|
|
117
|
+
type AuthResolver = (request: Request) => Promise<RequestAuth | null>;
|
|
118
|
+
/** Configuration for a proxying dispatch. */
|
|
119
|
+
interface DispatchConfig {
|
|
120
|
+
/** Origin the tools are proxied to, e.g. "https://app.example.com". */
|
|
121
|
+
baseUrl: string;
|
|
122
|
+
/** The caller's bearer, forwarded as `Authorization: Bearer <token>`. */
|
|
123
|
+
bearer: string;
|
|
124
|
+
/** Injectable fetch (defaults to global fetch) — eases testing. */
|
|
125
|
+
fetchImpl?: typeof fetch;
|
|
126
|
+
}
|
|
127
|
+
/** The upstream response, normalized for the MCP layer. */
|
|
128
|
+
interface DispatchResult {
|
|
129
|
+
status: number;
|
|
130
|
+
ok: boolean;
|
|
131
|
+
/** Parsed JSON body when the response was JSON, else the raw text. */
|
|
132
|
+
body: unknown;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Minimal structural view of the OpenAPI 3.x document we consume. We intentionally
|
|
137
|
+
* model only the subset the generator reads; unknown fields are ignored and any
|
|
138
|
+
* `$ref` in a leaf schema is forwarded opaquely (the document is expected to be
|
|
139
|
+
* dereferenced by the loader for anything we need to introspect — request-body
|
|
140
|
+
* object properties in particular).
|
|
141
|
+
*/
|
|
142
|
+
interface OpenApiOperation {
|
|
143
|
+
operationId?: string;
|
|
144
|
+
summary?: string;
|
|
145
|
+
description?: string;
|
|
146
|
+
tags?: string[];
|
|
147
|
+
/** Paladira's required projection of MCP tool annotations into OpenAPI. */
|
|
148
|
+
"x-mcp-tool-annotations"?: ToolAnnotations;
|
|
149
|
+
/** Dotted response paths stripped from the result before the agent sees it. */
|
|
150
|
+
"x-mcp-redact-response"?: readonly string[];
|
|
151
|
+
parameters?: OpenApiParameter[];
|
|
152
|
+
requestBody?: OpenApiRequestBody;
|
|
153
|
+
responses?: Record<string, OpenApiResponse>;
|
|
154
|
+
security?: Array<Record<string, string[]>>;
|
|
155
|
+
}
|
|
156
|
+
interface OpenApiParameter {
|
|
157
|
+
name: string;
|
|
158
|
+
in: string;
|
|
159
|
+
required?: boolean;
|
|
160
|
+
schema?: JsonSchema;
|
|
161
|
+
}
|
|
162
|
+
interface OpenApiRequestBody {
|
|
163
|
+
required?: boolean;
|
|
164
|
+
content?: Record<string, {
|
|
165
|
+
schema?: JsonSchema;
|
|
166
|
+
}>;
|
|
167
|
+
}
|
|
168
|
+
interface OpenApiResponse {
|
|
169
|
+
content?: Record<string, {
|
|
170
|
+
schema?: JsonSchema;
|
|
171
|
+
}>;
|
|
172
|
+
}
|
|
173
|
+
interface OpenApiDocument {
|
|
174
|
+
paths?: Record<string, Record<string, OpenApiOperation>>;
|
|
175
|
+
security?: Array<Record<string, string[]>>;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Generate one {@link GeneratedTool} per OpenAPI operation. Deterministic: the
|
|
179
|
+
* same document always yields the same tools in path/method declaration order,
|
|
180
|
+
* which is what makes the drift gate (`mcp:check`) a stable diff.
|
|
181
|
+
*/
|
|
182
|
+
declare function generateTools(doc: OpenApiDocument, options?: GenerateOptions): GeneratedTool[];
|
|
183
|
+
|
|
184
|
+
export { type AuthResolver as A, type DispatchConfig as D, type GeneratedTool as G, type JsonSchema as J, type OpenApiDocument as O, type ParameterLocation as P, type RequestAuth as R, type ToolManifest as T, type DispatchResult as a, type ToolAnnotations as b, type GenerateOptions as c, type OpenApiOperation as d, type OpenApiParameter as e, type OpenApiRequestBody as f, type OpenApiResponse as g, type ToolParameter as h, generateTools as i };
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI-integration guide content — the reusable copy for a store's "Integração com
|
|
3
|
+
* IA" onboarding. Pure, public, non-sensitive text (no React) so the on-page
|
|
4
|
+
* walkthrough stays a portable, testable content module. Host brand marks/icons
|
|
5
|
+
* and colours live in the components. Apps may pass their own overrides to
|
|
6
|
+
* `<AiIntegrationOnboarding>`; these are the shared defaults.
|
|
7
|
+
*
|
|
8
|
+
* The MCP endpoint URL is NOT hardcoded here — the app derives it per request
|
|
9
|
+
* from the deployment origin and passes it in.
|
|
10
|
+
*/
|
|
11
|
+
/** Which brand a host belongs to — drives the icon/accent in the UI. */
|
|
12
|
+
type AiHostBrand = "claude" | "openai";
|
|
13
|
+
interface AiHostLink {
|
|
14
|
+
/** Deep-link straight to the host's connector settings, when one exists. */
|
|
15
|
+
url: string;
|
|
16
|
+
label: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* One stage of the "configure the connector" part of the flow. A host can split
|
|
20
|
+
* configuration across several stages, each with its OWN deep link, step label
|
|
21
|
+
* and instructions — e.g. ChatGPT needs "enable developer mode" (Security
|
|
22
|
+
* settings) and then "configurar" (create the connector). When a host declares
|
|
23
|
+
* `configureStages`, the wizard renders one wizard step per stage (between
|
|
24
|
+
* "Copiar URL" and "Confirmar") instead of the default Configurar/Conectar
|
|
25
|
+
* split, and the sign-in happens inside a stage — no prompt to paste.
|
|
26
|
+
*/
|
|
27
|
+
interface AiHostConfigureStage {
|
|
28
|
+
/** Stable id — also the wizard step id + test id suffix (`ai-stage-${id}`). */
|
|
29
|
+
id: string;
|
|
30
|
+
/** Step label shown in the stepper. */
|
|
31
|
+
label: string;
|
|
32
|
+
/** Optional deep link opened on this stage (unlocks "Próximo" once opened). */
|
|
33
|
+
link?: AiHostLink;
|
|
34
|
+
/** The instructions shown for this stage. */
|
|
35
|
+
steps: readonly string[];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The AI providers a connection can be attributed to — derived server-side from
|
|
39
|
+
* the OAuth client's redirect URIs (and confirmed by the `announceAiConnection`
|
|
40
|
+
* tool). Drives which host card lights up green on the status board.
|
|
41
|
+
*/
|
|
42
|
+
type AiProvider = "claude" | "chatgpt" | "codex";
|
|
43
|
+
/** The provider a host id belongs to (claude-desktop shares Claude's provider). */
|
|
44
|
+
declare function providerForHostId(hostId: string): AiProvider | null;
|
|
45
|
+
interface AiHostGuide {
|
|
46
|
+
/** Stable id — also the panel test id suffix (`ai-setup-${id}`). */
|
|
47
|
+
id: string;
|
|
48
|
+
/** Tab label shown to the owner. */
|
|
49
|
+
label: string;
|
|
50
|
+
brand: AiHostBrand;
|
|
51
|
+
/** One-line hint of what this host is (web app, desktop app, CLI…). */
|
|
52
|
+
kind: string;
|
|
53
|
+
/** Optional direct link button (desktop apps have no deep link). */
|
|
54
|
+
link?: AiHostLink;
|
|
55
|
+
/**
|
|
56
|
+
* Optional link to the host's OFFICIAL connector docs — a stable vendor URL
|
|
57
|
+
* shown as a "Para mais informações" reference (never a deep link with a
|
|
58
|
+
* volatile connector id / UI params).
|
|
59
|
+
*/
|
|
60
|
+
docs?: AiHostLink;
|
|
61
|
+
steps: readonly string[];
|
|
62
|
+
/**
|
|
63
|
+
* Optional per-stage configuration (each with its own deep link + label). When
|
|
64
|
+
* present, the wizard renders one step per stage in place of the default
|
|
65
|
+
* Configurar → Conectar split, and `steps` mirrors the flattened stage
|
|
66
|
+
* instructions so the MCP guide stays a single source of truth.
|
|
67
|
+
*/
|
|
68
|
+
configureStages?: readonly AiHostConfigureStage[];
|
|
69
|
+
/**
|
|
70
|
+
* Optional deep link to a PUBLISHED one-click plugin/connector for this host
|
|
71
|
+
* (set per app via env, e.g. `CHATGPT_PLUGIN_URL` / `CLAUDE_PLUGIN_URL`). When
|
|
72
|
+
* present, the wizard swaps the manual "copy URL + configure connector" path
|
|
73
|
+
* for a simplified "open → Install → authorize" flow: the owner never copies
|
|
74
|
+
* the MCP URL. Absent → the full manual flow.
|
|
75
|
+
*/
|
|
76
|
+
pluginUrl?: string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The AI hosts a store owner can connect, in recommended order. Same OAuth flow
|
|
80
|
+
* everywhere (the host drives it) — only the menu path differs per app.
|
|
81
|
+
*
|
|
82
|
+
* A FUNCTION of the platform's name, because one step is not generic: the
|
|
83
|
+
* ChatGPT connector's consent screen shows an OAuth button labelled with
|
|
84
|
+
* whoever operates the server, and the owner is told which button to click. It
|
|
85
|
+
* used to name one particular STORE on one particular deployment — not even the
|
|
86
|
+
* product, a tenant of it — so every other adopter instructed its owners to
|
|
87
|
+
* click a button that does not exist.
|
|
88
|
+
*/
|
|
89
|
+
declare function aiHostGuides(platformName: string): readonly AiHostGuide[];
|
|
90
|
+
interface AiCapability {
|
|
91
|
+
/** Stable id — maps to an icon in the component. */
|
|
92
|
+
id: string;
|
|
93
|
+
/** Card headline. */
|
|
94
|
+
title: string;
|
|
95
|
+
/** Short supporting line, usually an example prompt in quotes. */
|
|
96
|
+
detail: string;
|
|
97
|
+
}
|
|
98
|
+
/** What a connected assistant does for the owner — one marketing card each. */
|
|
99
|
+
declare const AI_CAPABILITIES: readonly AiCapability[];
|
|
100
|
+
/**
|
|
101
|
+
* The permission model in one line, shown prominently: the assistant acts AS
|
|
102
|
+
* the signed-in owner (auth-passthrough) — it can do exactly what the owner
|
|
103
|
+
* can, nothing more, and no extra credential/API key is ever created.
|
|
104
|
+
*/
|
|
105
|
+
declare const AI_PERMISSION_MODEL = "O assistente age em seu nome, com exatamente as suas permiss\u00F5es: ele pode fazer o que voc\u00EA pode fazer na sua loja \u2014 nada al\u00E9m disso. N\u00E3o \u00E9 preciso criar nenhuma chave ou credencial extra; a autoriza\u00E7\u00E3o usa o seu pr\u00F3prio login.";
|
|
106
|
+
/** The two tools the paste-in prompt drives, and what to call the store id. */
|
|
107
|
+
interface AiConnectPromptSpec {
|
|
108
|
+
/**
|
|
109
|
+
* The tool that REGISTERS the connection server-side, so the store learns
|
|
110
|
+
* which assistant connected.
|
|
111
|
+
*/
|
|
112
|
+
announceTool: string;
|
|
113
|
+
/** A real READ tool, called straight after, to prove the access works. */
|
|
114
|
+
probeTool: string;
|
|
115
|
+
/** What that read returns, in the owner's own words ("o estoque da loja"). */
|
|
116
|
+
probeSubject: string;
|
|
117
|
+
/** What the assistant should ask for if it needs to identify the store. */
|
|
118
|
+
identifierName: string;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The message the owner pastes into the assistant's chat right after
|
|
122
|
+
* connecting: announce the connection, then read something real to prove it
|
|
123
|
+
* works. The owner types nothing.
|
|
124
|
+
*
|
|
125
|
+
* BUILT from the host's tool names rather than shipped with them. This was a
|
|
126
|
+
* constant naming two tools — `announceAiConnection` and `listInventory` — that
|
|
127
|
+
* THIS PACKAGE does not define or serve; they belong to one adopter's surface.
|
|
128
|
+
* Any other host handed its owner a prompt instructing the assistant to call
|
|
129
|
+
* two tools that do not exist, and because nothing registered the connection,
|
|
130
|
+
* the wizard's confirm step then waited forever for a state that could never
|
|
131
|
+
* arrive.
|
|
132
|
+
*/
|
|
133
|
+
declare function aiConnectPrompt(spec: AiConnectPromptSpec): string;
|
|
134
|
+
|
|
135
|
+
export { AI_CAPABILITIES as A, AI_PERMISSION_MODEL as a, type AiCapability as b, type AiConnectPromptSpec as c, type AiHostBrand as d, type AiHostConfigureStage as e, type AiHostGuide as f, type AiHostLink as g, type AiProvider as h, aiConnectPrompt as i, aiHostGuides as j, providerForHostId as p };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { A as ApiMcpOauth, M as McpOauthConfig } from '../create-api-mcp-oauth-CwVXKK-A.js';
|
|
3
|
+
import 'jose';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* `@12-apps/mcp/hono` — the OAuth authorization server as a mountable router.
|
|
7
|
+
*
|
|
8
|
+
* Behind its own subpath with `hono` as an OPTIONAL peer (the report-builder / rbac
|
|
9
|
+
* precedent), so a host on another framework — or one importing only the tool
|
|
10
|
+
* generator — never resolves it.
|
|
11
|
+
*
|
|
12
|
+
* Mounted at the ORIGIN ROOT, because two of the six paths are `.well-known`
|
|
13
|
+
* documents and a connector reads them from the origin, not from a prefix:
|
|
14
|
+
*
|
|
15
|
+
* const oauth = mcpOauthRouter({ stores, resolveSession });
|
|
16
|
+
* app.route('/', oauth.router);
|
|
17
|
+
*
|
|
18
|
+
* The adapter is deliberately thin: each handler already answers a Fetch `Response`
|
|
19
|
+
* (a 302 with a `Location`, RFC 6749 JSON, an RFC 8414 document), and those shapes
|
|
20
|
+
* are fixed by specification — there is no envelope to apply, and applying one
|
|
21
|
+
* would break every client.
|
|
22
|
+
*/
|
|
23
|
+
interface McpOauthHono extends ApiMcpOauth {
|
|
24
|
+
router: Hono;
|
|
25
|
+
}
|
|
26
|
+
declare function mcpOauthRouter(config: McpOauthConfig): McpOauthHono;
|
|
27
|
+
|
|
28
|
+
export { type McpOauthHono, mcpOauthRouter };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createApiMcpOauth
|
|
3
|
+
} from "../chunk-UIILEGAC.js";
|
|
4
|
+
import "../chunk-WJJNKKNS.js";
|
|
5
|
+
import {
|
|
6
|
+
__name
|
|
7
|
+
} from "../chunk-7QVYU63E.js";
|
|
8
|
+
|
|
9
|
+
// src/hono/index.ts
|
|
10
|
+
import { Hono } from "hono";
|
|
11
|
+
function mcpOauthRouter(config) {
|
|
12
|
+
const api = createApiMcpOauth(config);
|
|
13
|
+
const router = new Hono();
|
|
14
|
+
for (const route of api.routes) {
|
|
15
|
+
const handler = /* @__PURE__ */ __name((c) => route.handle(c.req.raw), "handler");
|
|
16
|
+
if (route.method === "GET") router.get(route.path, handler);
|
|
17
|
+
else router.post(route.path, handler);
|
|
18
|
+
}
|
|
19
|
+
return { ...api, router };
|
|
20
|
+
}
|
|
21
|
+
__name(mcpOauthRouter, "mcpOauthRouter");
|
|
22
|
+
export {
|
|
23
|
+
mcpOauthRouter
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hono/index.ts"],"sourcesContent":["import { Hono } from \"hono\";\nimport type { Context } from \"hono\";\n\nimport {\n createApiMcpOauth,\n type ApiMcpOauth,\n} from \"../oauth/create-api-mcp-oauth\";\nimport type { McpOauthConfig } from \"../oauth/context\";\n\n/**\n * `@12-apps/mcp/hono` — the OAuth authorization server as a mountable router.\n *\n * Behind its own subpath with `hono` as an OPTIONAL peer (the report-builder / rbac\n * precedent), so a host on another framework — or one importing only the tool\n * generator — never resolves it.\n *\n * Mounted at the ORIGIN ROOT, because two of the six paths are `.well-known`\n * documents and a connector reads them from the origin, not from a prefix:\n *\n * const oauth = mcpOauthRouter({ stores, resolveSession });\n * app.route('/', oauth.router);\n *\n * The adapter is deliberately thin: each handler already answers a Fetch `Response`\n * (a 302 with a `Location`, RFC 6749 JSON, an RFC 8414 document), and those shapes\n * are fixed by specification — there is no envelope to apply, and applying one\n * would break every client.\n */\nexport interface McpOauthHono extends ApiMcpOauth {\n router: Hono;\n}\n\nexport function mcpOauthRouter(config: McpOauthConfig): McpOauthHono {\n const api = createApiMcpOauth(config);\n const router = new Hono();\n\n for (const route of api.routes) {\n const handler = (c: Context): Promise<Response> => route.handle(c.req.raw);\n if (route.method === \"GET\") router.get(route.path, handler);\n else router.post(route.path, handler);\n }\n\n return { ...api, router };\n}\n"],"mappings":";;;;;;;;;AAAA,SAAS,YAAY;AA+Bd,SAAS,eAAe,QAAsC;AACnE,QAAM,MAAM,kBAAkB,MAAM;AACpC,QAAM,SAAS,IAAI,KAAK;AAExB,aAAW,SAAS,IAAI,QAAQ;AAC9B,UAAM,UAAU,wBAAC,MAAkC,MAAM,OAAO,EAAE,IAAI,GAAG,GAAzD;AAChB,QAAI,MAAM,WAAW,MAAO,QAAO,IAAI,MAAM,MAAM,OAAO;AAAA,QACrD,QAAO,KAAK,MAAM,MAAM,OAAO;AAAA,EACtC;AAEA,SAAO,EAAE,GAAG,KAAK,OAAO;AAC1B;AAXgB;","names":[]}
|