@exposify/express 0.3.2 → 0.3.3

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.
Files changed (2) hide show
  1. package/README.md +94 -0
  2. package/package.json +8 -4
package/README.md CHANGED
@@ -0,0 +1,94 @@
1
+ # @exposify/express — setup guide
2
+
3
+ Turn an existing Express app into an MCP server in one line: an
4
+ auto-generated **MCP endpoint** at `/mcp` lets AI agents (Claude, Cursor,
5
+ ChatGPT, or anything else speaking MCP) call your routes as tools, and an
6
+ embedded **knowledge base** built from your README/docs lets them understand
7
+ your product. No external services, no build step.
8
+
9
+ ```ts
10
+ import { aiReady } from "@exposify/express";
11
+
12
+ app.use(aiReady()); // MCP endpoint live at /mcp
13
+ ```
14
+
15
+ Auth is **passthrough**: every tool call carries exactly the caller's own
16
+ credentials (`Authorization`/`Cookie`), forwarded to your routes unchanged.
17
+ There is no separate authorization layer to configure or get wrong — an
18
+ agent can do exactly what the person it's acting for could already do.
19
+
20
+ ## Exposure policy
21
+
22
+ - **Reads (GET/HEAD) are exposed automatically.** Writes are hidden by
23
+ default — opt them in explicitly, right where the route is defined:
24
+
25
+ ```ts
26
+ import { aiReady, exposed, describe } from "@exposify/express";
27
+ import { z } from "zod";
28
+
29
+ app.post("/orders", exposed(createOrder));
30
+
31
+ // Or opt in while also enriching the tool's name/description/input schema:
32
+ app.post("/orders/:id/refund", describe(refundOrder, {
33
+ name: "refund_order",
34
+ description: "Refund an order. Reversible within 30 days.",
35
+ input: { id: z.string(), body: z.object({ reason: z.string() }) },
36
+ }));
37
+ ```
38
+
39
+ - **`describe()`'s `input` envelope contract:** `input` is a flat Zod shape.
40
+ At call time, each top-level key is routed by name — a key matching one of
41
+ the route's `:param` segments becomes a path substitution, `query`
42
+ (expected to be an object) becomes the query string, `body` becomes the
43
+ JSON request body. Any other top-level key is silently dropped and never
44
+ reaches the route (a one-time warning is logged per tool at registration
45
+ if this happens) — nest fields under `body` or `query` instead of putting
46
+ them at the top level.
47
+
48
+ ## Mounted routers
49
+
50
+ Routers mounted with `app.use(path, router)` **after** `aiReady()` (the
51
+ standard layout above) are discovered automatically on both Express 4 and 5.
52
+ Anything mounted *before* `aiReady()`, or a sub-app (Express can't
53
+ distinguish a sub-app from arbitrary middleware), needs an explicit entry:
54
+
55
+ ```ts
56
+ app.use(aiReady({ mounts: { "/legacy": legacyRouter } }));
57
+ ```
58
+
59
+ ## Options
60
+
61
+ ```ts
62
+ aiReady({
63
+ auth?: "passthrough" | "none", // default "passthrough"
64
+ docs?: string[], // default ["README.md", "docs/**/*.md"]
65
+ expose?: string[] | "*", // e.g. ["GET /trends"]; default unset
66
+ exclude?: string[], // picomatch globs against the route path
67
+ docsAuth?: "public" | "required", // default "public"
68
+ embedder?: (texts: string[]) => Promise<number[][]>,
69
+ telemetry?: { enabled: boolean; sink?(event): void; capturePayloads?: boolean },
70
+ cwd?: string, // default process.cwd()
71
+ mounts?: Record<string, unknown>, // explicit router/sub-app overrides
72
+ });
73
+ ```
74
+
75
+ Exposure precedence: an `exposed()`/`hidden()`/`describe()` marker on a
76
+ route always wins, then `exclude`, then `expose`, then the read/write
77
+ default above.
78
+
79
+ ## Known limitations
80
+
81
+ - **Sub-apps** (`app.use(path, subApp)`) are never auto-detected on any
82
+ Express version — always list them in `mounts` explicitly.
83
+ - **Express 5** can't reflect a mounted router's own path, so auto-discovery
84
+ only works when `aiReady()` is registered *before* the mount. A router
85
+ mounted both before and after `aiReady()` ("straddle" mount) resolves
86
+ correctly on Express 4 but silently drops the earlier prefix on Express 5.
87
+ - In-process dispatch uses `light-my-request`, which splices Express's
88
+ process-wide request/response prototypes for the duration of each
89
+ dispatch — a narrow concurrency window under real concurrent traffic, a
90
+ known tradeoff tracked in `packages/express/src/surface.ts`.
91
+
92
+ See the [repo README](https://github.com/ayadagain/agentready#readme) for
93
+ the full picture across all `@exposify/*` packages, including
94
+ `@exposify/supabase`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exposify/express",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -23,7 +23,7 @@
23
23
  "prepack": "yarn build"
24
24
  },
25
25
  "dependencies": {
26
- "@exposify/core": "0.3.2",
26
+ "@exposify/core": "1.0.0",
27
27
  "light-my-request": "^6.0.0"
28
28
  },
29
29
  "peerDependencies": {
@@ -52,9 +52,13 @@
52
52
  "bugs": {
53
53
  "url": "https://github.com/ayadagain/agentready/issues"
54
54
  },
55
- "description": "test",
55
+ "description": "Turn an Express app into an MCP server in one line: routes become AI agent tools automatically, writes are opt-in, and the caller's own credentials pass straight through.",
56
56
  "author": "Exposify",
57
57
  "keywords": [
58
- "aa"
58
+ "mcp",
59
+ "model-context-protocol",
60
+ "express",
61
+ "ai-agents",
62
+ "llm-tools"
59
63
  ]
60
64
  }