@lynq/lynq 0.2.0 → 0.4.0
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/README.md +79 -139
- package/dist/adapters/express.d.ts +1 -1
- package/dist/adapters/hono.d.ts +1 -1
- package/dist/chunk-2KEVF6YL.mjs +1 -0
- package/dist/chunk-L7SD7KKW.mjs +1 -0
- package/dist/chunk-STWVQGX5.mjs +1 -0
- package/dist/chunk-VAAZWX4U.mjs +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +1 -1
- package/dist/middleware/auth.d.ts +6 -8
- package/dist/middleware/auth.mjs +1 -1
- package/dist/middleware/bearer.d.ts +19 -0
- package/dist/middleware/bearer.mjs +1 -0
- package/dist/middleware/combine.d.ts +12 -0
- package/dist/middleware/combine.mjs +1 -0
- package/dist/middleware/credentials.d.ts +19 -0
- package/dist/middleware/credentials.mjs +1 -0
- package/dist/middleware/github-oauth.d.ts +42 -0
- package/dist/middleware/github-oauth.mjs +2 -0
- package/dist/middleware/google-oauth.d.ts +43 -0
- package/dist/middleware/google-oauth.mjs +2 -0
- package/dist/middleware/guard.d.ts +15 -0
- package/dist/middleware/guard.mjs +1 -0
- package/dist/middleware/jwt.d.ts +27 -0
- package/dist/middleware/jwt.mjs +1 -0
- package/dist/middleware/logger.d.ts +11 -0
- package/dist/middleware/logger.mjs +1 -0
- package/dist/middleware/oauth.d.ts +22 -0
- package/dist/middleware/oauth.mjs +1 -0
- package/dist/middleware/payment.d.ts +22 -0
- package/dist/middleware/payment.mjs +1 -0
- package/dist/middleware/rate-limit.d.ts +15 -0
- package/dist/middleware/rate-limit.mjs +1 -0
- package/dist/middleware/truncate.d.ts +13 -0
- package/dist/middleware/truncate.mjs +1 -0
- package/dist/middleware/url-action.d.ts +24 -0
- package/dist/middleware/url-action.mjs +1 -0
- package/dist/test.d.ts +1 -1
- package/dist/{types-BqH9Me9B.d.ts → types-CqT2idkd.d.ts} +48 -24
- package/package.json +61 -3
package/README.md
CHANGED
|
@@ -1,181 +1,121 @@
|
|
|
1
1
|
# lynq
|
|
2
2
|
|
|
3
3
|
[](https://github.com/hogekai/lynq/actions/workflows/ci.yml)
|
|
4
|
-
[](https://www.npmjs.com/package/lynq)
|
|
4
|
+
[](https://www.npmjs.com/package/@lynq/lynq)
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
MCP servers are stateless by default. lynq makes them session-aware.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
import { createMCPServer } from "lynq";
|
|
10
|
-
import { auth } from "lynq/auth";
|
|
11
|
-
import { z } from "zod";
|
|
8
|
+
## The Problem
|
|
12
9
|
|
|
13
|
-
|
|
10
|
+
With the official SDK, adding session-aware tool visibility requires manual plumbing:
|
|
14
11
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
12
|
+
```ts
|
|
13
|
+
// Without lynq — manual session tracking, manual notifications
|
|
14
|
+
const sessions = new Map();
|
|
15
|
+
|
|
16
|
+
server.setRequestHandler(ListToolsRequestSchema, (req, extra) => {
|
|
17
|
+
const session = sessions.get(extra.sessionId);
|
|
18
|
+
const tools = [loginTool];
|
|
19
|
+
if (session?.authorized) tools.push(weatherTool); // manual filtering
|
|
20
|
+
return { tools };
|
|
23
21
|
});
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
23
|
+
server.setRequestHandler(CallToolRequestSchema, async (req, extra) => {
|
|
24
|
+
if (req.params.name === "login") {
|
|
25
|
+
sessions.set(extra.sessionId, { authorized: true });
|
|
26
|
+
server.sendToolListChanged(); // manual notification
|
|
27
|
+
}
|
|
28
|
+
// ...
|
|
32
29
|
});
|
|
30
|
+
```
|
|
33
31
|
|
|
34
|
-
|
|
32
|
+
## The Solution
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
// With lynq — one line
|
|
36
|
+
server.tool("weather", guard(), config, handler);
|
|
37
|
+
// Client gets notified automatically. No manual wiring.
|
|
35
38
|
```
|
|
36
39
|
|
|
37
40
|
## Install
|
|
38
41
|
|
|
39
42
|
```sh
|
|
40
|
-
npm install lynq
|
|
43
|
+
npm install @lynq/lynq
|
|
41
44
|
```
|
|
42
45
|
|
|
43
|
-
##
|
|
44
|
-
|
|
45
|
-
When you build an MCP server, you often need to show different tools depending on session state — hide admin tools from unauthenticated users, reveal features after onboarding, etc. The MCP protocol supports this via bidirectional tool list notifications, but wiring it by hand means managing visibility sets, diffing tool lists, and calling `sendToolListChanged` at the right time. lynq lets you declare visibility as middleware and handles the rest.
|
|
46
|
-
|
|
47
|
-
## API
|
|
48
|
-
|
|
49
|
-
### `createMCPServer(info)`
|
|
50
|
-
|
|
51
|
-
Creates a server instance.
|
|
46
|
+
## Quick Start
|
|
52
47
|
|
|
53
48
|
```ts
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
### `server.tool(name, ...middlewares?, config, handler)`
|
|
58
|
-
|
|
59
|
-
Register a tool. Middlewares are optional, config holds `description` and `input` schema.
|
|
49
|
+
import { createMCPServer } from "@lynq/lynq";
|
|
50
|
+
import { guard } from "@lynq/lynq/guard";
|
|
51
|
+
import { z } from "zod";
|
|
60
52
|
|
|
61
|
-
|
|
62
|
-
server.tool("greet", {
|
|
63
|
-
description: "Greet someone",
|
|
64
|
-
input: z.object({ name: z.string() }),
|
|
65
|
-
}, async (args) => ({
|
|
66
|
-
content: [{ type: "text", text: `Hello ${args.name}` }],
|
|
67
|
-
}));
|
|
68
|
-
|
|
69
|
-
server.tool("secret", auth(), {
|
|
70
|
-
input: z.object({ query: z.string() }),
|
|
71
|
-
}, async (args) => ({
|
|
72
|
-
content: [{ type: "text", text: args.query }],
|
|
73
|
-
}));
|
|
74
|
-
```
|
|
53
|
+
const server = createMCPServer({ name: "my-server", version: "1.0.0" });
|
|
75
54
|
|
|
76
|
-
|
|
55
|
+
server.tool("login", {
|
|
56
|
+
input: z.object({ username: z.string(), password: z.string() }),
|
|
57
|
+
}, async (args, c) => {
|
|
58
|
+
const user = await authenticate(args.username, args.password);
|
|
59
|
+
c.session.set("user", user);
|
|
60
|
+
c.session.authorize("guard");
|
|
61
|
+
return c.text(`Welcome, ${user.name}`);
|
|
62
|
+
});
|
|
77
63
|
|
|
78
|
-
|
|
64
|
+
server.tool("weather", guard(), {
|
|
65
|
+
description: "Get weather for a city",
|
|
66
|
+
input: z.object({ city: z.string() }),
|
|
67
|
+
}, async (args, c) => {
|
|
68
|
+
return c.text(JSON.stringify(await fetchWeather(args.city)));
|
|
69
|
+
});
|
|
79
70
|
|
|
80
|
-
|
|
81
|
-
server.resource("config://settings", {
|
|
82
|
-
name: "App Settings",
|
|
83
|
-
mimeType: "application/json",
|
|
84
|
-
}, async (uri) => ({
|
|
85
|
-
text: JSON.stringify(config),
|
|
86
|
-
}));
|
|
87
|
-
|
|
88
|
-
server.resource("data://users", auth(), {
|
|
89
|
-
name: "User Database",
|
|
90
|
-
mimeType: "application/json",
|
|
91
|
-
}, async (uri, ctx) => ({
|
|
92
|
-
text: JSON.stringify(await db.getUsers()),
|
|
93
|
-
}));
|
|
71
|
+
await server.stdio();
|
|
94
72
|
```
|
|
95
73
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
Apply middleware to all subsequently registered tools.
|
|
99
|
-
|
|
100
|
-
```ts
|
|
101
|
-
server.use(auth());
|
|
74
|
+
```sh
|
|
75
|
+
npx tsx server.ts
|
|
102
76
|
```
|
|
103
77
|
|
|
104
|
-
|
|
78
|
+
## Features
|
|
105
79
|
|
|
106
|
-
|
|
80
|
+
- **Session-Scoped Visibility** — `authorize()` shows tools, `revoke()` hides them. Client notification is automatic.
|
|
81
|
+
- **Hono-Style Middleware** — Global via `server.use()`, per-tool inline. Three hooks: `onRegister`, `onCall`, `onResult`.
|
|
82
|
+
- **Built-in Middleware** — `guard()` `rateLimit()` `logger()` `truncate()` `credentials()` `some()` `every()` `except()`
|
|
83
|
+
- **Response Helpers** — `c.text()` `c.json()` `c.error()` `c.image()` — chainable: `c.text("done").json({ id: 1 })`
|
|
84
|
+
- **Elicitation** — `c.elicit.form(message, zodSchema)` for structured user input. `c.elicit.url()` for external flows.
|
|
85
|
+
- **Framework Adapters** — `server.http()` returns `(Request) => Response`. Mount in Hono, Express, Deno, Workers.
|
|
86
|
+
- **Test Helpers** — `createTestClient()` for in-memory testing. No transport setup.
|
|
87
|
+
- **Tiny Core** — One dependency. ESM only. No config files, no magic.
|
|
107
88
|
|
|
108
|
-
|
|
109
|
-
ctx.session.set("key", value);
|
|
110
|
-
ctx.session.get("key");
|
|
111
|
-
ctx.session.authorize("auth"); // Enable tools guarded by "auth" middleware
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
### `auth(options?)`
|
|
115
|
-
|
|
116
|
-
Middleware that hides tools until authenticated.
|
|
89
|
+
## Middleware Composition
|
|
117
90
|
|
|
118
91
|
```ts
|
|
119
|
-
import {
|
|
92
|
+
import { guard } from "@lynq/lynq/guard";
|
|
93
|
+
import { rateLimit } from "@lynq/lynq/rate-limit";
|
|
94
|
+
import { logger } from "@lynq/lynq/logger";
|
|
120
95
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
auth({ message: "Login first" }); // custom error message
|
|
96
|
+
server.use(logger()); // global
|
|
97
|
+
server.tool("search", guard(), rateLimit({ max: 10 }), config, handler); // per-tool stack
|
|
124
98
|
```
|
|
125
99
|
|
|
126
|
-
##
|
|
100
|
+
## Comparison
|
|
127
101
|
|
|
128
|
-
|
|
102
|
+
| | lynq | FastMCP | Official SDK |
|
|
103
|
+
|---|---|---|---|
|
|
104
|
+
| Per-tool middleware | Yes | No | No |
|
|
105
|
+
| Session-scoped visibility | Auto-notify | Manual | Manual |
|
|
106
|
+
| onResult hook | Yes | No | No |
|
|
107
|
+
| Response helpers | Chainable | Basic | No |
|
|
108
|
+
| Test helpers | Yes | No | No |
|
|
109
|
+
| HTTP server built-in | No (you choose) | Yes (opinionated) | No |
|
|
129
110
|
|
|
130
|
-
|
|
131
|
-
import { createTestClient } from "lynq/test";
|
|
132
|
-
import { createMCPServer } from "lynq";
|
|
133
|
-
import { auth } from "lynq/auth";
|
|
134
|
-
import { z } from "zod";
|
|
111
|
+
## Documentation
|
|
135
112
|
|
|
136
|
-
|
|
137
|
-
server.tool("weather", auth(), {
|
|
138
|
-
input: z.object({ city: z.string() }),
|
|
139
|
-
}, async (args) => ({
|
|
140
|
-
content: [{ type: "text", text: `Sunny in ${args.city}` }],
|
|
141
|
-
}));
|
|
142
|
-
|
|
143
|
-
const t = await createTestClient(server);
|
|
144
|
-
|
|
145
|
-
// Tool visibility
|
|
146
|
-
const tools = await t.listTools(); // string[]
|
|
147
|
-
expect(tools).not.toContain("weather");
|
|
148
|
-
|
|
149
|
-
// Authorize and call
|
|
150
|
-
t.authorize("auth");
|
|
151
|
-
const text = await t.callToolText("weather", { city: "Tokyo" });
|
|
152
|
-
expect(text).toContain("Sunny");
|
|
153
|
-
|
|
154
|
-
// Full result access
|
|
155
|
-
const result = await t.callTool("weather", { city: "Tokyo" });
|
|
156
|
-
|
|
157
|
-
// Resources
|
|
158
|
-
const uris = await t.listResources();
|
|
159
|
-
const content = await t.readResource("config://settings");
|
|
160
|
-
|
|
161
|
-
// Session access
|
|
162
|
-
t.session.set("user", { name: "alice" });
|
|
113
|
+
[https://hogekai.github.io/lynq/](https://hogekai.github.io/lynq/)
|
|
163
114
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
Optional vitest/jest matchers for more expressive assertions:
|
|
170
|
-
|
|
171
|
-
```ts
|
|
172
|
-
import { matchers } from "lynq/test";
|
|
173
|
-
expect.extend(matchers);
|
|
174
|
-
|
|
175
|
-
const result = await t.callTool("weather", { city: "Tokyo" });
|
|
176
|
-
expect(result).toHaveTextContent("Sunny");
|
|
177
|
-
expect(result).not.toBeError();
|
|
178
|
-
```
|
|
115
|
+
- [Quick Start](https://hogekai.github.io/lynq/getting-started/quick-start)
|
|
116
|
+
- [Middleware Concepts](https://hogekai.github.io/lynq/concepts/middleware)
|
|
117
|
+
- [Why lynq](https://hogekai.github.io/lynq/why-lynq)
|
|
118
|
+
- [API Reference](https://hogekai.github.io/lynq/api-reference/)
|
|
179
119
|
|
|
180
120
|
## License
|
|
181
121
|
|
package/dist/adapters/hono.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {a}from'./chunk-STWVQGX5.mjs';function n(e){let t={name:e.name??"oauth",sessionKey:e.sessionKey??"user",message:e.message??"Please sign in to continue.",buildUrl:e.buildUrl,declineMessage:"Authentication cancelled."};return e.timeout!==void 0&&(t.timeout=e.timeout),a(t)}export{n as a};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {c}from'./chunk-VAAZWX4U.mjs';function g(e){let s=e?.name??"guard",n=e?.sessionKey??"user",t=e?.message??"Authorization required.";return {name:s,onRegister(){return false},async onCall(o,a){return o.session.get(n)?a():c(t)}}}export{g as a};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {c}from'./chunk-VAAZWX4U.mjs';function m(e){let n=e.name??"url-action",i=e.sessionKey??"user",l=e.timeout??3e5,a=e.declineMessage??"Action cancelled.";return {name:n,onRegister(){return false},async onCall(s,r){if(s.session.get(i))return r();let o=crypto.randomUUID(),c$1=e.buildUrl({sessionId:s.sessionId,elicitationId:o});return (await s.elicit.url(e.message,c$1,{elicitationId:o,waitForCompletion:true,timeout:l})).action!=="accept"?c(a):s.session.get(i)?(s.session.authorize(n),r()):c("Action was not completed.")}}}export{m as a};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function t(e,n){return {content:e,...n?{isError:true}:{},text(o){return t([...e,{type:"text",text:o}],n)},json(o){return t([...e,{type:"text",text:JSON.stringify(o,null,2)}],n)},error(o){return t([...e,{type:"text",text:o}],true)},image(o,r){return t([...e,{type:"image",data:o,mimeType:r}],n)}}}function s(e){return t([{type:"text",text:e}])}function l(e){return t([{type:"text",text:JSON.stringify(e,null,2)}])}function p(e){return t([{type:"text",text:e}],true)}function i(e,n){return t([{type:"image",data:e,mimeType:n}])}export{s as a,l as b,p as c,i as d};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { M as MCPServer } from './types-
|
|
2
|
-
export { E as Elicit, a as
|
|
1
|
+
import { M as MCPServer } from './types-CqT2idkd.js';
|
|
2
|
+
export { E as Elicit, a as ElicitFormResult, b as ElicitUrlOptions, c as ElicitUrlResult, H as HttpAdapterOptions, R as ResourceConfig, d as ResourceContent, e as ResourceContext, f as ResourceHandler, g as RootInfo, S as Sample, h as SampleOptions, i as SampleRawParams, j as SampleRawResult, k as ServerInfo, l as Session, T as TaskConfig, m as TaskContext, n as TaskControl, o as TaskHandler, p as ToolConfig, q as ToolContext, r as ToolHandler, s as ToolInfo, t as ToolMiddleware, u as ToolResponse, v as error, w as image, x as json, y as text } from './types-CqT2idkd.js';
|
|
3
3
|
import '@modelcontextprotocol/sdk/types.js';
|
|
4
4
|
import 'zod';
|
|
5
5
|
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import {InMemoryTaskStore}from'@modelcontextprotocol/sdk/experimental/tasks';import {Server}from'@modelcontextprotocol/sdk/server/index.js';import {ListToolsRequestSchema,CallToolRequestSchema,ListResourcesRequestSchema,ListResourceTemplatesRequestSchema,ReadResourceRequestSchema}from'@modelcontextprotocol/sdk/types.js';import {normalizeObjectSchema}from'@modelcontextprotocol/sdk/server/zod-compat.js';import {toJsonSchemaCompat}from'@modelcontextprotocol/sdk/server/zod-json-schema-compat.js';function ne(a){return {async form({message:l,schema:c}){let i=await a.elicitInput({message:l,requestedSchema:{type:"object",properties:c}});return {action:i.action,content:i.content??{}}},async url({message:l,url:c}){return {action:(await a.elicitInput({mode:"url",message:l,url:c,elicitationId:crypto.randomUUID()})).action}}}}function A(a){return async()=>{try{return (await a.listRoots()).roots.map(c=>{let i={uri:c.uri};return c.name!==void 0&&(i.name=c.name),i})}catch{return []}}}function se(a){async function l(i,u){let p={messages:[{role:"user",content:{type:"text",text:i}}],maxTokens:u?.maxTokens??1024};u?.model!==void 0&&(p.modelPreferences={hints:[{name:u.model}]}),u?.system!==void 0&&(p.systemPrompt=u.system),u?.temperature!==void 0&&(p.temperature=u.temperature),u?.stopSequences!==void 0&&(p.stopSequences=u.stopSequences);let f=(await a.createMessage(p)).content;return f.type==="text"?f.text:""}async function c(i){return a.createMessage(i)}return Object.assign(l,{raw:c})}function q(a,l,c,i,u){return {toolName:i,session:c,signal:u,sessionId:l,elicit:ne(a),roots:A(a),sample:se(a)}}function B(a){if(a==null)return {type:"object"};let l=normalizeObjectSchema(a);return l?toJsonSchemaCompat(l):a}function H(a,l){let c=l[l.length-1];if(typeof c!="function")throw new TypeError(`${a}: last argument must be a handler function`);let i=l[l.length-2];if(i==null||typeof i!="object"||Array.isArray(i))throw new TypeError(`${a}: second-to-last argument must be a config object`);let u=l.slice(0,-2);for(let p of u)if(!p||typeof p!="object"||typeof p.name!="string")throw new TypeError(`${a}: each middleware must have a "name" property`);return {middlewares:u,config:i,handler:c}}function j(a,l){let c=[];for(let i of l)i.onRegister?.(a)===false&&c.push(i.name);return c}function L(a){let c=a.split(/\{[^}]+\}/).map(i=>i.replace(/[.*+?^$|()[\]\\]/g,"\\$&"));return new RegExp(`^${c.join("(.+)")}$`)}function E(a,l,c,i){let u=c.get(l);if(u==="disabled")return false;if(u==="enabled")return true;for(let p of a)if(!i.has(p))return false;return true}function z(a,l){let c=a.get(l);if(c)return c;for(let i of a.values())if(i.isTemplate&&i.uriPattern?.test(l))return i}function $(a,l,c){let i=a.filter(f=>f.onCall),u=a.filter(f=>f.onResult).reverse(),p=0,y=async()=>{if(p>=i.length){let b=await c();for(let C of u)b=await C.onResult(b,l);return b}return i[p++].onCall(l,y)};return y}function pe(a){let l=[],c=new Map,i=new Map,u=new Map,p=new Map,y=new Map,f=new Set,b=new InMemoryTaskStore,C=new Proxy(b,{get(e,n,t){return n==="updateTaskStatus"?async(s,r,...o)=>(r==="cancelled"&&f.add(s),e.updateTaskStatus.call(e,s,r,...o)):Reflect.get(e,n,t)}}),h=new Server(a,{capabilities:{tools:{listChanged:true},resources:{listChanged:true},tasks:{list:{},cancel:{},requests:{tools:{call:{}}}}},taskStore:C});function S(e){let n=p.get(e);return n||(n={data:new Map,grants:new Set,toolOverrides:new Map,resourceOverrides:new Map},p.set(e,n)),n}function O(e,n){let t=S(n);return E(e.hiddenByMiddlewares,e.name,t.toolOverrides,t.grants)}function k(e,n){let t=S(n);return E(e.hiddenByMiddlewares,e.uri,t.resourceOverrides,t.grants)}function _(e,n){let t=S(n);return E(e.hiddenByMiddlewares,e.name,t.toolOverrides,t.grants)}function M(e){(e&&y.get(e)||h).sendToolListChanged().catch(()=>{});}function x(e){(e&&y.get(e)||h).sendResourceListChanged().catch(()=>{});}function I(e){let n=S(e);return {get(t){return n.data.get(t)},set(t,s){n.data.set(t,s);},authorize(t){n.grants.add(t),M(e),x(e);},revoke(t){n.grants.delete(t),M(e),x(e);},enableTools(...t){for(let s of t)n.toolOverrides.set(s,"enabled");M(e);},disableTools(...t){for(let s of t)n.toolOverrides.set(s,"disabled");M(e);},enableResources(...t){for(let s of t)n.resourceOverrides.set(s,"enabled");x(e);},disableResources(...t){for(let s of t)n.resourceOverrides.set(s,"disabled");x(e);}}}function V(e){e.setRequestHandler(ListToolsRequestSchema,(n,t)=>{let s=t.sessionId??"default",r=[];for(let o of c.values())O(o,s)&&r.push({name:o.name,description:o.description,inputSchema:B(o.input)});for(let o of u.values())_(o,s)&&r.push({name:o.name,description:o.description,inputSchema:B(o.input),execution:{taskSupport:"required"}});return {tools:r}}),e.setRequestHandler(CallToolRequestSchema,async(n,t)=>{let{name:s,arguments:r}=n.params,o=t.sessionId??"default",w=d=>({content:[{type:"text",text:d}],isError:true}),g=c.get(s);if(g){if(!O(g,o))return w(`Tool not available: ${s}`);let d=q(e,o,I(o),s,t.signal),v=()=>Promise.resolve(g.handler(r??{},d));return $(g.middlewares,d,v)()}let T=u.get(s);if(T){if(!_(T,o))return w(`Tool not available: ${s}`);let d=t.taskStore;if(!d)return w("Task store not available");let v=await d.createTask({pollInterval:1e3}),m=v.taskId,Y={progress(R,P){if(f.has(m))return;let te=P?`${R}% ${P}`:`${R}%`;d.updateTaskStatus(m,"working",te).catch(()=>{});},get cancelled(){return f.has(m)}},J={...q(e,o,I(o),s,t.signal),task:Y},ee=async()=>((async()=>{try{let R=await T.handler(r??{},J);f.has(m)||await d.storeTaskResult(m,"completed",R);}catch(R){if(!f.has(m)){let P=R instanceof Error?R.message:String(R);await d.storeTaskResult(m,"failed",{content:[{type:"text",text:P}],isError:true}).catch(()=>{});}}})(),{task:v});return $(T.middlewares,J,ee)()}return w(`Unknown tool: ${s}`)}),e.setRequestHandler(ListResourcesRequestSchema,(n,t)=>{let s=t.sessionId??"default",r=[];for(let o of i.values())!o.isTemplate&&k(o,s)&&r.push({uri:o.uri,name:o.name,description:o.description,mimeType:o.mimeType});return {resources:r}}),e.setRequestHandler(ListResourceTemplatesRequestSchema,(n,t)=>{let s=t.sessionId??"default",r=[];for(let o of i.values())o.isTemplate&&k(o,s)&&r.push({uriTemplate:o.uri,name:o.name,description:o.description,mimeType:o.mimeType});return {resourceTemplates:r}}),e.setRequestHandler(ReadResourceRequestSchema,async(n,t)=>{let{uri:s}=n.params,r=z(i,s);if(!r)throw new Error(`Unknown resource: ${s}`);let o=t.sessionId??"default";if(!k(r,o))throw new Error(`Resource not available: ${s}`);let w=I(o),g={uri:s,session:w,sessionId:o,roots:A(e)},T=q(e,o,w,r.uri,t.signal),d=async()=>{let m=await r.handler(s,g);return {contents:[{uri:s,mimeType:m.mimeType??r.mimeType,...m.text!=null?{text:m.text}:{},...m.blob!=null?{blob:m.blob}:{}}]}};return $(r.middlewares,T,d)()});}V(h);function F(e){l.push(e);}function G(...e){let n=e[0],t=H(`tool("${n}")`,e.slice(1));if(typeof t.config.name=="string")throw new TypeError(`tool("${n}"): second-to-last argument must be a config object`);let s=t.config,r=[...l,...t.middlewares],o={name:n,description:s.description,middlewares:r};c.set(n,{name:n,description:s.description,input:s.input,handler:t.handler,middlewares:r,hiddenByMiddlewares:j(o,r)});}function D(...e){let n=e[0],t=H(`resource("${n}")`,e.slice(1));if(typeof t.config.name!="string")throw new TypeError(`resource("${n}"): second-to-last argument must be a config object with a "name" property`);let s=t.config,r={name:s.name,description:s.description,middlewares:t.middlewares},o=n.includes("{");i.set(n,{uri:n,isTemplate:o,uriPattern:o?L(n):null,name:s.name,description:s.description,mimeType:s.mimeType,handler:t.handler,middlewares:t.middlewares,hiddenByMiddlewares:j(r,t.middlewares)});}function W(...e){let n=e[0],t=H(`task("${n}")`,e.slice(1));if(typeof t.config.name=="string")throw new TypeError(`task("${n}"): second-to-last argument must be a config object`);let s=t.config,r=[...l,...t.middlewares],o={name:n,description:s.description,middlewares:r};u.set(n,{name:n,description:s.description,input:s.input,handler:t.handler,middlewares:r,hiddenByMiddlewares:j(o,r)});}async function Z(){let{StdioServerTransport:e}=await import('@modelcontextprotocol/sdk/server/stdio.js'),n=new e;await h.connect(n);}async function K(e){await h.connect(e);}let Q={tools:{listChanged:true},resources:{listChanged:true},tasks:{list:{},cancel:{},requests:{tools:{call:{}}}}};function U(){let e=new Server(a,{capabilities:Q,taskStore:C});return V(e),e}function X(e){let n=null;async function t(){return n||(n=(await import('@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js')).WebStandardStreamableHTTPServerTransport),n}if(e?.sessionless)return async r=>{let o=await t(),w=U(),g=new o({sessionIdGenerator:void 0,enableJsonResponse:e?.enableJsonResponse});return await w.connect(g),g.handleRequest(r)};let s=new Map;return async r=>{let o=await t(),w=r.headers.get("mcp-session-id");if(w){let d=s.get(w);return d?d.transport.handleRequest(r):new Response(JSON.stringify({jsonrpc:"2.0",error:{code:-32e3,message:"Session not found"}}),{status:404,headers:{"Content-Type":"application/json"}})}let g=U(),T=new o({sessionIdGenerator:e?.sessionIdGenerator??(()=>crypto.randomUUID()),enableJsonResponse:e?.enableJsonResponse,onsessioninitialized:d=>{s.set(d,{server:g,transport:T}),y.set(d,g);},onsessionclosed:d=>{s.delete(d),y.delete(d);}});return await g.connect(T),T.handleRequest(r)}}return {use:F,tool:G,resource:D,task:W,stdio:Z,http:X,connect:K,_server:h,_getSession:S,_isToolVisible(e,n){let t=c.get(e);return t?O(t,n):false},_isResourceVisible(e,n){let t=i.get(e);return t?k(t,n):false},_isTaskVisible(e,n){let t=u.get(e);return t?_(t,n):false},_createSessionAPI:I}}export{pe as createMCPServer};
|
|
1
|
+
import {c,d,b,a}from'./chunk-VAAZWX4U.mjs';export{c as error,d as image,b as json,a as text}from'./chunk-VAAZWX4U.mjs';import {InMemoryTaskStore}from'@modelcontextprotocol/sdk/experimental/tasks';import {Server}from'@modelcontextprotocol/sdk/server/index.js';import {ListToolsRequestSchema,CallToolRequestSchema,ListResourcesRequestSchema,ListResourceTemplatesRequestSchema,ReadResourceRequestSchema}from'@modelcontextprotocol/sdk/types.js';import {normalizeObjectSchema}from'@modelcontextprotocol/sdk/server/zod-compat.js';import {toJsonSchemaCompat}from'@modelcontextprotocol/sdk/server/zod-json-schema-compat.js';function j(a){if(a==null)return {type:"object"};let l=normalizeObjectSchema(a);return l?toJsonSchemaCompat(l):a}function $(a,l){let c=l[l.length-1];if(typeof c!="function")throw new TypeError(`${a}: last argument must be a handler function`);let i=l[l.length-2];if(i==null||typeof i!="object"||Array.isArray(i))throw new TypeError(`${a}: second-to-last argument must be a config object`);let d=l.slice(0,-2);for(let u of d)if(!u||typeof u!="object"||typeof u.name!="string")throw new TypeError(`${a}: each middleware must have a "name" property`);return {middlewares:d,config:i,handler:c}}function A(a,l){let c=[];for(let i of l)i.onRegister?.(a)===false&&c.push(i.name);return c}function Q(a){let c=a.split(/\{[^}]+\}/).map(i=>i.replace(/[.*+?^$|()[\]\\]/g,"\\$&"));return new RegExp(`^${c.join("(.+)")}$`)}function B(a,l,c,i){let d=c.get(l);if(d==="disabled")return false;if(d==="enabled")return true;for(let u of a)if(!i.has(u))return false;return true}function X(a,l){let c=a.get(l);if(c)return c;for(let i of a.values())if(i.isTemplate&&i.uriPattern?.test(l))return i}function U(a,l,c){let i=a.filter(m=>m.onCall),d=a.filter(m=>m.onResult).reverse(),u=0,p=async()=>{if(u>=i.length){let S=await c();for(let C of d)S=await C.onResult(S,l);return S}return i[u++].onCall(l,p)};return p}function pe(a,l,c){return {async form(i,d){let u=j(d),p=await a.elicitInput({message:i,requestedSchema:u});return {action:p.action,content:p.content??{}}},async url(i,d,u){let p=u?.elicitationId??crypto.randomUUID(),m;u?.waitForCompletion&&l&&(m=l(p,a));let S=await a.elicitInput({mode:"url",message:i,url:d,elicitationId:p});if(S.action==="accept"&&m){let C=u?.timeout??3e5,x=new Promise((G,I)=>{setTimeout(()=>I(new Error("Elicitation timed out")),C);});await Promise.race([m,x]);}else m&&c&&c(p);return {action:S.action}}}}function F(a){return async()=>{try{return (await a.listRoots()).roots.map(c=>{let i={uri:c.uri};return c.name!==void 0&&(i.name=c.name),i})}catch{return []}}}function fe(a){async function l(i,d){let u={messages:[{role:"user",content:{type:"text",text:i}}],maxTokens:d?.maxTokens??1024};d?.model!==void 0&&(u.modelPreferences={hints:[{name:d.model}]}),d?.system!==void 0&&(u.systemPrompt=d.system),d?.temperature!==void 0&&(u.temperature=d.temperature),d?.stopSequences!==void 0&&(u.stopSequences=d.stopSequences);let m=(await a.createMessage(u)).content;return m.type==="text"?m.text:""}async function c(i){return a.createMessage(i)}return Object.assign(l,{raw:c})}function N(a$1,l,c$1,i,d$1,u,p){return {toolName:i,session:c$1,signal:d$1,sessionId:l,elicit:pe(a$1,u,p),roots:F(a$1),sample:fe(a$1),text:a,json:b,error:c,image:d}}function ve(a){let l=[],c$1=new Map,i=new Map,d=new Map,u=new Map,p=new Map,m=new Map,S=36e5;function C(){let e=Date.now();for(let[t,n]of m)e-n.createdAt>S&&m.delete(t);}function x(e,t,n){return C(),new Promise(o=>{let r;try{r=n.createElicitationCompletionNotifier(e);}catch{}m.set(e,{resolver:o,completionNotifier:r,createdAt:Date.now()});})}function G(e){C();let t=m.get(e);t&&(m.delete(e),t.completionNotifier&&t.completionNotifier().catch(()=>{}),t.resolver());}function I(e){let t=m.get(e);t&&(m.delete(e),t.resolver());}let q=new Set,ee=new InMemoryTaskStore,W=new Proxy(ee,{get(e,t,n){return t==="updateTaskStatus"?async(o,r,...s)=>(r==="cancelled"&&q.add(o),e.updateTaskStatus.call(e,o,r,...s)):Reflect.get(e,t,n)}}),k=new Server(a,{capabilities:{tools:{listChanged:true},resources:{listChanged:true},tasks:{list:{},cancel:{},requests:{tools:{call:{}}}}},taskStore:W});function E(e){let t=u.get(e);return t||(t={data:new Map,grants:new Set,toolOverrides:new Map,resourceOverrides:new Map},u.set(e,t)),t}function V(e,t){let n=E(t);return B(e.hiddenByMiddlewares,e.name,n.toolOverrides,n.grants)}function H(e,t){let n=E(t);return B(e.hiddenByMiddlewares,e.uri,n.resourceOverrides,n.grants)}function J(e,t){let n=E(t);return B(e.hiddenByMiddlewares,e.name,n.toolOverrides,n.grants)}function O(e){(e&&p.get(e)||k).sendToolListChanged().catch(()=>{});}function _(e){(e&&p.get(e)||k).sendResourceListChanged().catch(()=>{});}function b(e){let t=E(e);return {get(n){return t.data.get(n)},set(n,o){t.data.set(n,o);},authorize(n){t.grants.add(n),O(e),_(e);},revoke(n){t.grants.delete(n),O(e),_(e);},enableTools(...n){for(let o of n)t.toolOverrides.set(o,"enabled");O(e);},disableTools(...n){for(let o of n)t.toolOverrides.set(o,"disabled");O(e);},enableResources(...n){for(let o of n)t.resourceOverrides.set(o,"enabled");_(e);},disableResources(...n){for(let o of n)t.resourceOverrides.set(o,"disabled");_(e);}}}function Z(e){e.setRequestHandler(ListToolsRequestSchema,(t,n)=>{let o=n.sessionId??"default",r=[];for(let s of c$1.values())V(s,o)&&r.push({name:s.name,description:s.description,inputSchema:j(s.input)});for(let s of d.values())J(s,o)&&r.push({name:s.name,description:s.description,inputSchema:j(s.input),execution:{taskSupport:"required"}});return {tools:r}}),e.setRequestHandler(CallToolRequestSchema,async(t,n)=>{let{name:o,arguments:r}=t.params,s=n.sessionId??"default",g=c$1.get(o);if(g){if(!V(g,s))return c(`Tool not available: ${o}`);let w=N(e,s,b(s),o,n.signal,(R,M)=>x(R,s,M),I),f=()=>Promise.resolve(g.handler(r??{},w));return U(g.middlewares,w,f)()}let T=d.get(o);if(T){if(!J(T,s))return c(`Tool not available: ${o}`);let w=n.taskStore;if(!w)return c("Task store not available");let f=await w.createTask({pollInterval:1e3}),h=f.taskId,R={progress(y,P){if(q.has(h))return;let de=P?`${y}% ${P}`:`${y}%`;w.updateTaskStatus(h,"working",de).catch(()=>{});},get cancelled(){return q.has(h)}},M={...N(e,s,b(s),o,n.signal,(y,P)=>x(y,s,P),I),task:R},ce=async()=>((async()=>{try{let y=await T.handler(r??{},M);q.has(h)||await w.storeTaskResult(h,"completed",y);}catch(y){if(!q.has(h)){let P=y instanceof Error?y.message:String(y);await w.storeTaskResult(h,"failed",c(P)).catch(()=>{});}}})(),{task:f});return U(T.middlewares,M,ce)()}return c(`Unknown tool: ${o}`)}),e.setRequestHandler(ListResourcesRequestSchema,(t,n)=>{let o=n.sessionId??"default",r=[];for(let s of i.values())!s.isTemplate&&H(s,o)&&r.push({uri:s.uri,name:s.name,description:s.description,mimeType:s.mimeType});return {resources:r}}),e.setRequestHandler(ListResourceTemplatesRequestSchema,(t,n)=>{let o=n.sessionId??"default",r=[];for(let s of i.values())s.isTemplate&&H(s,o)&&r.push({uriTemplate:s.uri,name:s.name,description:s.description,mimeType:s.mimeType});return {resourceTemplates:r}}),e.setRequestHandler(ReadResourceRequestSchema,async(t,n)=>{let{uri:o}=t.params,r=X(i,o);if(!r)throw new Error(`Unknown resource: ${o}`);let s=n.sessionId??"default";if(!H(r,s))throw new Error(`Resource not available: ${o}`);let g=b(s),T={uri:o,session:g,sessionId:s,roots:F(e)},w=N(e,s,g,r.uri,n.signal,(R,M)=>x(R,s,M),I),f=async()=>{let R=await r.handler(o,T);return {contents:[{uri:o,mimeType:R.mimeType??r.mimeType,...R.text!=null?{text:R.text}:{},...R.blob!=null?{blob:R.blob}:{}}]}};return U(r.middlewares,w,f)()});}Z(k);function te(e){l.push(e);}function ne(...e){let t=e[0],n=$(`tool("${t}")`,e.slice(1));if(typeof n.config.name=="string")throw new TypeError(`tool("${t}"): second-to-last argument must be a config object`);let o=n.config,r=[...l,...n.middlewares],s={name:t,description:o.description,middlewares:r};c$1.set(t,{name:t,description:o.description,input:o.input,handler:n.handler,middlewares:r,hiddenByMiddlewares:A(s,r)});}function oe(...e){let t=e[0],n=$(`resource("${t}")`,e.slice(1));if(typeof n.config.name!="string")throw new TypeError(`resource("${t}"): second-to-last argument must be a config object with a "name" property`);let o=n.config,r={name:o.name,description:o.description,middlewares:n.middlewares},s=t.includes("{");i.set(t,{uri:t,isTemplate:s,uriPattern:s?Q(t):null,name:o.name,description:o.description,mimeType:o.mimeType,handler:n.handler,middlewares:n.middlewares,hiddenByMiddlewares:A(r,n.middlewares)});}function se(...e){let t=e[0],n=$(`task("${t}")`,e.slice(1));if(typeof n.config.name=="string")throw new TypeError(`task("${t}"): second-to-last argument must be a config object`);let o=n.config,r=[...l,...n.middlewares],s={name:t,description:o.description,middlewares:r};d.set(t,{name:t,description:o.description,input:o.input,handler:n.handler,middlewares:r,hiddenByMiddlewares:A(s,r)});}async function re(){let{StdioServerTransport:e}=await import('@modelcontextprotocol/sdk/server/stdio.js'),t=new e;await k.connect(t);}async function ie(e){await k.connect(e);}let ae={tools:{listChanged:true},resources:{listChanged:true},tasks:{list:{},cancel:{},requests:{tools:{call:{}}}}};function K(){let e=new Server(a,{capabilities:ae,taskStore:W});return Z(e),e}function le(e){let t=null;async function n(){return t||(t=(await import('@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js')).WebStandardStreamableHTTPServerTransport),t}if(e?.sessionless)return async r=>{let s=await n(),g=K(),T=new s({sessionIdGenerator:void 0,enableJsonResponse:e?.enableJsonResponse});return await g.connect(T),T.handleRequest(r)};let o=new Map;return async r=>{let s=await n(),g=r.headers.get("mcp-session-id");if(g){let f=o.get(g);return f?(e?.onRequest&&await e.onRequest(r,g,b(g)),f.transport.handleRequest(r)):new Response(JSON.stringify({jsonrpc:"2.0",error:{code:-32e3,message:"Session not found"}}),{status:404,headers:{"Content-Type":"application/json"}})}let T=K(),w=new s({sessionIdGenerator:e?.sessionIdGenerator??(()=>crypto.randomUUID()),enableJsonResponse:e?.enableJsonResponse,onsessioninitialized:f=>{o.set(f,{server:T,transport:w}),p.set(f,T),e?.onRequest&&e.onRequest(r,f,b(f));},onsessionclosed:f=>{o.delete(f),p.delete(f);}});return await T.connect(w),w.handleRequest(r)}}return {use:te,tool:ne,resource:oe,task:se,stdio:re,http:le,session:b,completeElicitation:G,connect:ie,_server:k,_getSession:E,_isToolVisible(e,t){let n=c$1.get(e);return n?V(n,t):false},_isResourceVisible(e,t){let n=i.get(e);return n?H(n,t):false},_isTaskVisible(e,t){let n=d.get(e);return n?J(n,t):false},_createSessionAPI:b}}export{ve as createMCPServer};
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as ToolMiddleware } from '../types-CqT2idkd.js';
|
|
2
|
+
import { GuardOptions } from './guard.js';
|
|
2
3
|
import '@modelcontextprotocol/sdk/types.js';
|
|
3
4
|
import 'zod';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
message?: string;
|
|
10
|
-
}
|
|
11
|
-
declare function auth(options?: AuthOptions): ToolMiddleware;
|
|
6
|
+
/** @deprecated Use `GuardOptions` from `@lynq/lynq/guard` instead. */
|
|
7
|
+
type AuthOptions = GuardOptions;
|
|
8
|
+
/** @deprecated Use `guard()` from `@lynq/lynq/guard` instead. */
|
|
9
|
+
declare function auth(options?: GuardOptions): ToolMiddleware;
|
|
12
10
|
|
|
13
11
|
export { type AuthOptions, auth };
|
package/dist/middleware/auth.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
import {a}from'../chunk-L7SD7KKW.mjs';import'../chunk-VAAZWX4U.mjs';function e(o){return a({name:"auth",...o})}export{e as auth};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { t as ToolMiddleware } from '../types-CqT2idkd.js';
|
|
2
|
+
import '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
interface BearerOptions {
|
|
6
|
+
/** Middleware name. Default: "bearer" */
|
|
7
|
+
name?: string;
|
|
8
|
+
/** Session key where the raw token is stored. Default: "token" */
|
|
9
|
+
tokenKey?: string;
|
|
10
|
+
/** Session key to store verified user. Default: "user" */
|
|
11
|
+
sessionKey?: string;
|
|
12
|
+
/** Verify the token. Return user data or null/throw on failure. */
|
|
13
|
+
verify: (token: string) => Promise<unknown | null>;
|
|
14
|
+
/** Error message. Default: "Invalid or missing token." */
|
|
15
|
+
message?: string;
|
|
16
|
+
}
|
|
17
|
+
declare function bearer(options: BearerOptions): ToolMiddleware;
|
|
18
|
+
|
|
19
|
+
export { type BearerOptions, bearer };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {c}from'../chunk-VAAZWX4U.mjs';function y(e){let n=e.name??"bearer",m=e.tokenKey??"token",t=e.sessionKey??"user",o=e.message??"Invalid or missing token.";return {name:n,onRegister(){return false},async onCall(s,i){if(s.session.get(t))return i();let a=s.session.get(m);if(!a)return c(o);let g=await e.verify(a);return g?(s.session.set(t,g),s.session.authorize(n),i()):c(o)}}}export{y as bearer};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { t as ToolMiddleware, q as ToolContext } from '../types-CqT2idkd.js';
|
|
2
|
+
import '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
/** Run the first middleware that doesn't short-circuit. */
|
|
6
|
+
declare function some(...middlewares: ToolMiddleware[]): ToolMiddleware;
|
|
7
|
+
/** Run all middlewares. Stop if any short-circuits. */
|
|
8
|
+
declare function every(...middlewares: ToolMiddleware[]): ToolMiddleware;
|
|
9
|
+
/** Run middleware only when the condition is false. */
|
|
10
|
+
declare function except(condition: (c: ToolContext) => boolean, middleware: ToolMiddleware): ToolMiddleware;
|
|
11
|
+
|
|
12
|
+
export { every, except, some };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function f(...n){return {name:`some(${n.map(e=>e.name).join(",")})`,onRegister(e){for(let o of n)if(o.onRegister?.(e)===false)return false},async onCall(e,o){let t,r;for(let s of n){if(!s.onCall){t=s;break}let u=false,a=async()=>(u=true,o()),i=await s.onCall(e,a);if(u)return t=s,i;r=i;}return t?o():r},onResult(e){return e}}}function c(...n){let l=n.map(o=>o.name),e=n.filter(o=>o.onResult).reverse();return {name:`every(${l.join(",")})`,onRegister(o){for(let t of n)if(t.onRegister?.(o)===false)return false},async onCall(o,t){let r=n.filter(a=>a.onCall),s=0,u=async()=>s>=r.length?t():r[s++].onCall(o,u);return u()},onResult(o,t){let r=o;for(let s of e){let u=s.onResult(r,t);u instanceof Promise||(r=u);}return r}}}function T(n,l){return {name:`except(${l.name})`,onRegister(e){return l.onRegister?.(e)},async onCall(e,o){return n(e)?o():l.onCall?l.onCall(e,o):o()},onResult(e,o){return l.onResult?l.onResult(e,o):e}}}export{c as every,T as except,f as some};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { t as ToolMiddleware } from '../types-CqT2idkd.js';
|
|
3
|
+
import '@modelcontextprotocol/sdk/types.js';
|
|
4
|
+
|
|
5
|
+
interface CredentialsOptions<T extends z.ZodObject<z.ZodRawShape>> {
|
|
6
|
+
/** Middleware name. Default: "credentials" */
|
|
7
|
+
name?: string;
|
|
8
|
+
/** Message shown to the user. */
|
|
9
|
+
message: string;
|
|
10
|
+
/** Zod schema for the form fields. */
|
|
11
|
+
schema: T;
|
|
12
|
+
/** Verify the submitted credentials. Return user data or null. */
|
|
13
|
+
verify: (fields: z.infer<T>) => Promise<unknown | null>;
|
|
14
|
+
/** Session key to store verified user. Default: "user" */
|
|
15
|
+
sessionKey?: string;
|
|
16
|
+
}
|
|
17
|
+
declare function credentials<T extends z.ZodObject<z.ZodRawShape>>(options: CredentialsOptions<T>): ToolMiddleware;
|
|
18
|
+
|
|
19
|
+
export { type CredentialsOptions, credentials };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {c as c$1}from'../chunk-VAAZWX4U.mjs';function c(e){let r=e.name??"credentials",t=e.sessionKey??"user";return {name:r,onRegister(){return false},async onCall(s,i){if(s.session.get(t))return i();let a=await s.elicit.form(e.message,e.schema);if(a.action!=="accept")return c$1("Authentication cancelled.");let o=await e.verify(a.content);return o?(s.session.set(t,o),s.session.authorize(r),i()):c$1("Invalid credentials.")}}}export{c as credentials};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { t as ToolMiddleware, M as MCPServer } from '../types-CqT2idkd.js';
|
|
2
|
+
import '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
interface GitHubOAuthOptions {
|
|
6
|
+
/** Middleware name. Default: "github-oauth" */
|
|
7
|
+
name?: string;
|
|
8
|
+
/** GitHub OAuth App client ID. */
|
|
9
|
+
clientId: string;
|
|
10
|
+
/** GitHub OAuth App client secret. */
|
|
11
|
+
clientSecret: string;
|
|
12
|
+
/** OAuth callback URL (your server's callback endpoint). */
|
|
13
|
+
redirectUri: string;
|
|
14
|
+
/** GitHub OAuth scopes. Default: [] */
|
|
15
|
+
scopes?: string[];
|
|
16
|
+
/** Session key for user data. Default: "user" */
|
|
17
|
+
sessionKey?: string;
|
|
18
|
+
/** Message shown to the user. Default: "Please sign in with GitHub to continue." */
|
|
19
|
+
message?: string;
|
|
20
|
+
/** Timeout in ms. Default: 300000 */
|
|
21
|
+
timeout?: number;
|
|
22
|
+
}
|
|
23
|
+
declare function githubOAuth(options: GitHubOAuthOptions): ToolMiddleware;
|
|
24
|
+
interface HandleGitHubCallbackOptions {
|
|
25
|
+
clientId: string;
|
|
26
|
+
clientSecret: string;
|
|
27
|
+
/** Session key for user data. Default: "user" */
|
|
28
|
+
sessionKey?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Handle GitHub OAuth callback. Call from your HTTP callback route.
|
|
32
|
+
* Exchanges code for token, fetches user info, stores in session, and completes elicitation.
|
|
33
|
+
*/
|
|
34
|
+
declare function handleGitHubCallback(server: MCPServer, params: {
|
|
35
|
+
code: string;
|
|
36
|
+
state: string;
|
|
37
|
+
}, options: HandleGitHubCallbackOptions): Promise<{
|
|
38
|
+
success: boolean;
|
|
39
|
+
error?: string;
|
|
40
|
+
}>;
|
|
41
|
+
|
|
42
|
+
export { type GitHubOAuthOptions, type HandleGitHubCallbackOptions, githubOAuth, handleGitHubCallback };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import {a}from'../chunk-2KEVF6YL.mjs';import'../chunk-STWVQGX5.mjs';import'../chunk-VAAZWX4U.mjs';function h(e){let s=e.scopes??[],t={name:e.name??"github-oauth",sessionKey:e.sessionKey??"user",message:e.message??"Please sign in with GitHub to continue.",buildUrl({sessionId:c,elicitationId:n}){let r=new URLSearchParams({client_id:e.clientId,redirect_uri:e.redirectUri,state:`${c}:${n}`});return s.length>0&&r.set("scope",s.join(" ")),`https://github.com/login/oauth/authorize?${r}`}};return e.timeout!==void 0&&(t.timeout=e.timeout),a(t)}async function m(e,s,t){let c=t.sessionKey??"user",[n,r]=s.state.split(":");if(!n||!r)return {success:false,error:"Invalid state parameter"};try{let i=await(await fetch("https://github.com/login/oauth/access_token",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({client_id:t.clientId,client_secret:t.clientSecret,code:s.code})})).json();if(!i.access_token)return {success:!1,error:i.error_description??i.error??"Token exchange failed"};let l=await(await fetch("https://api.github.com/user",{headers:{Authorization:`Bearer ${i.access_token}`}})).json(),a=e.session(n);return a.set(c,l),a.set("accessToken",i.access_token),e.completeElicitation(r),{success:!0}}catch(o){return {success:false,error:o instanceof Error?o.message:String(o)}}}
|
|
2
|
+
export{h as githubOAuth,m as handleGitHubCallback};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { t as ToolMiddleware, M as MCPServer } from '../types-CqT2idkd.js';
|
|
2
|
+
import '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
interface GoogleOAuthOptions {
|
|
6
|
+
/** Middleware name. Default: "google-oauth" */
|
|
7
|
+
name?: string;
|
|
8
|
+
/** Google OAuth client ID. */
|
|
9
|
+
clientId: string;
|
|
10
|
+
/** Google OAuth client secret. */
|
|
11
|
+
clientSecret: string;
|
|
12
|
+
/** OAuth callback URL (your server's callback endpoint). */
|
|
13
|
+
redirectUri: string;
|
|
14
|
+
/** OAuth scopes. Default: ["openid", "profile", "email"] */
|
|
15
|
+
scopes?: string[];
|
|
16
|
+
/** Session key for user data. Default: "user" */
|
|
17
|
+
sessionKey?: string;
|
|
18
|
+
/** Message shown to the user. Default: "Please sign in with Google to continue." */
|
|
19
|
+
message?: string;
|
|
20
|
+
/** Timeout in ms. Default: 300000 */
|
|
21
|
+
timeout?: number;
|
|
22
|
+
}
|
|
23
|
+
declare function googleOAuth(options: GoogleOAuthOptions): ToolMiddleware;
|
|
24
|
+
interface HandleGoogleCallbackOptions {
|
|
25
|
+
clientId: string;
|
|
26
|
+
clientSecret: string;
|
|
27
|
+
redirectUri: string;
|
|
28
|
+
/** Session key for user data. Default: "user" */
|
|
29
|
+
sessionKey?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Handle Google OAuth callback. Call from your HTTP callback route.
|
|
33
|
+
* Exchanges code for tokens, fetches user info, stores in session, and completes elicitation.
|
|
34
|
+
*/
|
|
35
|
+
declare function handleGoogleCallback(server: MCPServer, params: {
|
|
36
|
+
code: string;
|
|
37
|
+
state: string;
|
|
38
|
+
}, options: HandleGoogleCallbackOptions): Promise<{
|
|
39
|
+
success: boolean;
|
|
40
|
+
error?: string;
|
|
41
|
+
}>;
|
|
42
|
+
|
|
43
|
+
export { type GoogleOAuthOptions, type HandleGoogleCallbackOptions, googleOAuth, handleGoogleCallback };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import {a}from'../chunk-2KEVF6YL.mjs';import'../chunk-STWVQGX5.mjs';import'../chunk-VAAZWX4U.mjs';function m(e){let r=e.scopes??["openid","profile","email"],t={name:e.name??"google-oauth",sessionKey:e.sessionKey??"user",message:e.message??"Please sign in with Google to continue.",buildUrl({sessionId:i,elicitationId:o}){return `https://accounts.google.com/o/oauth2/v2/auth?${new URLSearchParams({client_id:e.clientId,redirect_uri:e.redirectUri,response_type:"code",scope:r.join(" "),state:`${i}:${o}`,access_type:"offline"})}`}};return e.timeout!==void 0&&(t.timeout=e.timeout),a(t)}async function p(e,r,t){let i=t.sessionKey??"user",[o,c]=r.state.split(":");if(!o||!c)return {success:false,error:"Invalid state parameter"};try{let s=await(await fetch("https://oauth2.googleapis.com/token",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({code:r.code,client_id:t.clientId,client_secret:t.clientSecret,redirect_uri:t.redirectUri,grant_type:"authorization_code"})})).json();if(!s.access_token)return {success:!1,error:s.error_description??s.error??"Token exchange failed"};let d=await(await fetch("https://www.googleapis.com/oauth2/v2/userinfo",{headers:{Authorization:`Bearer ${s.access_token}`}})).json(),a=e.session(o);return a.set(i,d),a.set("accessToken",s.access_token),s.id_token&&a.set("idToken",s.id_token),e.completeElicitation(c),{success:!0}}catch(n){return {success:false,error:n instanceof Error?n.message:String(n)}}}
|
|
2
|
+
export{m as googleOAuth,p as handleGoogleCallback};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { t as ToolMiddleware } from '../types-CqT2idkd.js';
|
|
2
|
+
import '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
interface GuardOptions {
|
|
6
|
+
/** Middleware name. Used for authorize()/revoke(). Default: "guard" */
|
|
7
|
+
name?: string;
|
|
8
|
+
/** Session key to check. Default: "user" */
|
|
9
|
+
sessionKey?: string;
|
|
10
|
+
/** Error message when not authorized. */
|
|
11
|
+
message?: string;
|
|
12
|
+
}
|
|
13
|
+
declare function guard(options?: GuardOptions): ToolMiddleware;
|
|
14
|
+
|
|
15
|
+
export { type GuardOptions, guard };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{a as guard}from'../chunk-L7SD7KKW.mjs';import'../chunk-VAAZWX4U.mjs';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { t as ToolMiddleware } from '../types-CqT2idkd.js';
|
|
2
|
+
import '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
interface JwtOptions {
|
|
6
|
+
/** Middleware name. Default: "jwt" */
|
|
7
|
+
name?: string;
|
|
8
|
+
/** Session key where the raw token is stored. Default: "token" */
|
|
9
|
+
tokenKey?: string;
|
|
10
|
+
/** Session key to store decoded payload. Default: "user" */
|
|
11
|
+
sessionKey?: string;
|
|
12
|
+
/** Symmetric secret for HMAC verification. */
|
|
13
|
+
secret?: string;
|
|
14
|
+
/** JWKS URI for remote key fetching. */
|
|
15
|
+
jwksUri?: string;
|
|
16
|
+
/** Expected issuer claim. */
|
|
17
|
+
issuer?: string;
|
|
18
|
+
/** Expected audience claim. */
|
|
19
|
+
audience?: string;
|
|
20
|
+
/** Additional validation on the decoded payload. Return user data or null. */
|
|
21
|
+
validate?: (payload: Record<string, unknown>) => unknown | null | Promise<unknown | null>;
|
|
22
|
+
/** Error message. Default: "Invalid or expired JWT." */
|
|
23
|
+
message?: string;
|
|
24
|
+
}
|
|
25
|
+
declare function jwt(options: JwtOptions): ToolMiddleware;
|
|
26
|
+
|
|
27
|
+
export { type JwtOptions, jwt };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {c}from'../chunk-VAAZWX4U.mjs';function j(e){let u=e.name??"jwt",y=e.tokenKey??"token",l=e.sessionKey??"user",d=e.message??"Invalid or expired JWT.",s=null;function m(){return s||(s=import('jose').catch(()=>(s=null,null))),s}return {name:u,onRegister(){return false},async onCall(n,c$1){if(n.session.get(l))return c$1();let a=n.session.get(y);if(!a)return c("JWT required.");let t=await m();if(!t)return c("jose library is required for JWT middleware. Install it: pnpm add jose");try{let i;if(e.jwksUri){let o=t.createRemoteJWKSet(new URL(e.jwksUri));i=(await t.jwtVerify(a,o,{issuer:e.issuer,audience:e.audience})).payload;}else if(e.secret){let o=new TextEncoder().encode(e.secret);i=(await t.jwtVerify(a,o,{issuer:e.issuer,audience:e.audience})).payload;}else return c("JWT middleware misconfigured: provide secret or jwksUri.");let w=e.validate?await e.validate(i):i;return w?(n.session.set(l,w),n.session.authorize(u),c$1()):c(d)}catch{return c(d)}}}}export{j as jwt};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { t as ToolMiddleware } from '../types-CqT2idkd.js';
|
|
2
|
+
import '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
interface LoggerOptions {
|
|
6
|
+
/** Custom log function. Default: console.log */
|
|
7
|
+
log?: (message: string) => void;
|
|
8
|
+
}
|
|
9
|
+
declare function logger(options?: LoggerOptions): ToolMiddleware;
|
|
10
|
+
|
|
11
|
+
export { type LoggerOptions, logger };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function a(s){let e=s?.log??console.log;return {name:"logger",async onCall(o,t){let n=performance.now();e(`[${o.toolName}] called (session: ${o.sessionId})`);let r=await t(),l=(performance.now()-n).toFixed(1);return e(`[${o.toolName}] ${l}ms${r.isError?" ERROR":""}`),r}}}export{a as logger};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { t as ToolMiddleware } from '../types-CqT2idkd.js';
|
|
2
|
+
import '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
interface OAuthOptions {
|
|
6
|
+
/** Middleware name. Default: "oauth" */
|
|
7
|
+
name?: string;
|
|
8
|
+
/** Session key for storing tokens. Default: "user" */
|
|
9
|
+
sessionKey?: string;
|
|
10
|
+
/** Message shown to the user. Default: "Please sign in to continue." */
|
|
11
|
+
message?: string;
|
|
12
|
+
/** Build the OAuth authorization URL. */
|
|
13
|
+
buildUrl: (params: {
|
|
14
|
+
sessionId: string;
|
|
15
|
+
elicitationId: string;
|
|
16
|
+
}) => string;
|
|
17
|
+
/** Timeout in ms. Default: 300000 */
|
|
18
|
+
timeout?: number;
|
|
19
|
+
}
|
|
20
|
+
declare function oauth(options: OAuthOptions): ToolMiddleware;
|
|
21
|
+
|
|
22
|
+
export { type OAuthOptions, oauth };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{a as oauth}from'../chunk-2KEVF6YL.mjs';import'../chunk-STWVQGX5.mjs';import'../chunk-VAAZWX4U.mjs';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { t as ToolMiddleware } from '../types-CqT2idkd.js';
|
|
2
|
+
import '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
interface PaymentOptions {
|
|
6
|
+
/** Middleware name. Default: "payment" */
|
|
7
|
+
name?: string;
|
|
8
|
+
/** Session key for storing payment confirmation. Default: "payment" */
|
|
9
|
+
sessionKey?: string;
|
|
10
|
+
/** Message shown to the user. Default: "Please complete payment to continue." */
|
|
11
|
+
message?: string;
|
|
12
|
+
/** Build the payment page URL. */
|
|
13
|
+
buildUrl: (params: {
|
|
14
|
+
sessionId: string;
|
|
15
|
+
elicitationId: string;
|
|
16
|
+
}) => string;
|
|
17
|
+
/** Timeout in ms. Default: 300000 */
|
|
18
|
+
timeout?: number;
|
|
19
|
+
}
|
|
20
|
+
declare function payment(options: PaymentOptions): ToolMiddleware;
|
|
21
|
+
|
|
22
|
+
export { type PaymentOptions, payment };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {a}from'../chunk-STWVQGX5.mjs';import'../chunk-VAAZWX4U.mjs';function i(e){let t={name:e.name??"payment",sessionKey:e.sessionKey??"payment",message:e.message??"Please complete payment to continue.",buildUrl:e.buildUrl,declineMessage:"Payment cancelled."};return e.timeout!==void 0&&(t.timeout=e.timeout),a(t)}export{i as payment};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { t as ToolMiddleware } from '../types-CqT2idkd.js';
|
|
2
|
+
import '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
interface RateLimitOptions {
|
|
6
|
+
/** Maximum calls per window. */
|
|
7
|
+
max: number;
|
|
8
|
+
/** Window duration in milliseconds. Default: 60000 (1 minute) */
|
|
9
|
+
windowMs?: number;
|
|
10
|
+
/** Error message. */
|
|
11
|
+
message?: string;
|
|
12
|
+
}
|
|
13
|
+
declare function rateLimit(options: RateLimitOptions): ToolMiddleware;
|
|
14
|
+
|
|
15
|
+
export { type RateLimitOptions, rateLimit };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {c}from'../chunk-VAAZWX4U.mjs';function l(n){let{max:o,windowMs:r=6e4}=n,u=n.message??`Rate limit exceeded. Max ${o} calls per ${r/1e3}s.`;return {name:"rateLimit",async onCall(t,i){let s=`rateLimit:${t.toolName}`,e=t.session.get(s),a=Date.now();return !e||a>=e.resetAt?(t.session.set(s,{count:1,resetAt:a+r}),i()):e.count>=o?c(u):(t.session.set(s,{...e,count:e.count+1}),i())}}}export{l as rateLimit};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { t as ToolMiddleware } from '../types-CqT2idkd.js';
|
|
2
|
+
import '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
interface TruncateOptions {
|
|
6
|
+
/** Maximum characters per text content block. */
|
|
7
|
+
maxChars: number;
|
|
8
|
+
/** Suffix appended when truncated. Default: "..." */
|
|
9
|
+
suffix?: string;
|
|
10
|
+
}
|
|
11
|
+
declare function truncate(options: TruncateOptions): ToolMiddleware;
|
|
12
|
+
|
|
13
|
+
export { type TruncateOptions, truncate };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function a(e){let{maxChars:r}=e,n=e.suffix??"...";return {name:"truncate",onResult(s){return {...s,content:s.content.map(t=>t.type==="text"&&t.text&&t.text.length>r?{...t,text:t.text.slice(0,r-n.length)+n}:t)}}}}export{a as truncate};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { t as ToolMiddleware } from '../types-CqT2idkd.js';
|
|
2
|
+
import '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
interface UrlActionOptions {
|
|
6
|
+
/** Middleware name. Default: "url-action" */
|
|
7
|
+
name?: string;
|
|
8
|
+
/** Session key to check/store result. Default: "user" */
|
|
9
|
+
sessionKey?: string;
|
|
10
|
+
/** Message shown to the user in the elicitation. */
|
|
11
|
+
message: string;
|
|
12
|
+
/** Build the URL. Receives sessionId and elicitationId for callback routing. */
|
|
13
|
+
buildUrl: (params: {
|
|
14
|
+
sessionId: string;
|
|
15
|
+
elicitationId: string;
|
|
16
|
+
}) => string;
|
|
17
|
+
/** Timeout in ms for waiting for external callback. Default: 300000 (5 min). */
|
|
18
|
+
timeout?: number;
|
|
19
|
+
/** Error message when user declines. Default: "Action cancelled." */
|
|
20
|
+
declineMessage?: string;
|
|
21
|
+
}
|
|
22
|
+
declare function urlAction(options: UrlActionOptions): ToolMiddleware;
|
|
23
|
+
|
|
24
|
+
export { type UrlActionOptions, urlAction };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{a as urlAction}from'../chunk-STWVQGX5.mjs';import'../chunk-VAAZWX4U.mjs';
|
package/dist/test.d.ts
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
|
-
import { CreateMessageRequestParamsBase, CreateMessageResult
|
|
1
|
+
import { CallToolResult, CreateMessageRequestParamsBase, CreateMessageResult } from '@modelcontextprotocol/sdk/types.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
|
|
4
|
+
interface ToolResponse extends CallToolResult {
|
|
5
|
+
text(value: string): ToolResponse;
|
|
6
|
+
json(value: unknown): ToolResponse;
|
|
7
|
+
error(message: string): ToolResponse;
|
|
8
|
+
image(data: string, mimeType: string): ToolResponse;
|
|
9
|
+
}
|
|
10
|
+
/** Create a text response. Chainable. */
|
|
11
|
+
declare function text(value: string): ToolResponse;
|
|
12
|
+
/** Create a JSON response (serialized to text). Chainable. */
|
|
13
|
+
declare function json(value: unknown): ToolResponse;
|
|
14
|
+
/** Create an error response. Chainable. */
|
|
15
|
+
declare function error(message: string): ToolResponse;
|
|
16
|
+
/** Create an image response. Chainable. */
|
|
17
|
+
declare function image(data: string, mimeType: string): ToolResponse;
|
|
18
|
+
|
|
4
19
|
interface ServerInfo {
|
|
5
20
|
name: string;
|
|
6
21
|
version: string;
|
|
@@ -23,31 +38,26 @@ interface Session {
|
|
|
23
38
|
/** Disable specific resources by URI. */
|
|
24
39
|
disableResources(...uris: string[]): void;
|
|
25
40
|
}
|
|
26
|
-
interface
|
|
27
|
-
message: string;
|
|
28
|
-
schema: Record<string, {
|
|
29
|
-
type: "string" | "number" | "boolean";
|
|
30
|
-
description?: string;
|
|
31
|
-
enum?: string[];
|
|
32
|
-
default?: unknown;
|
|
33
|
-
}>;
|
|
34
|
-
}
|
|
35
|
-
interface ElicitFormResult {
|
|
41
|
+
interface ElicitFormResult<T = Record<string, string | number | boolean | string[]>> {
|
|
36
42
|
action: "accept" | "decline" | "cancel";
|
|
37
|
-
content:
|
|
38
|
-
}
|
|
39
|
-
interface ElicitUrlParams {
|
|
40
|
-
message: string;
|
|
41
|
-
url: string;
|
|
43
|
+
content: T;
|
|
42
44
|
}
|
|
43
45
|
interface ElicitUrlResult {
|
|
44
46
|
action: "accept" | "decline" | "cancel";
|
|
45
47
|
}
|
|
48
|
+
interface ElicitUrlOptions {
|
|
49
|
+
/** Pre-generated elicitation ID. If omitted, a random UUID is used. */
|
|
50
|
+
elicitationId?: string;
|
|
51
|
+
/** If true, wait for completeElicitation() before resolving. Default: false. */
|
|
52
|
+
waitForCompletion?: boolean;
|
|
53
|
+
/** Timeout in ms for waiting. Default: 300000 (5 minutes). */
|
|
54
|
+
timeout?: number;
|
|
55
|
+
}
|
|
46
56
|
interface Elicit {
|
|
47
57
|
/** Request structured data from the user via a form. */
|
|
48
|
-
form(
|
|
58
|
+
form<T extends z.ZodObject<z.ZodRawShape>>(message: string, schema: T): Promise<ElicitFormResult<z.infer<T>>>;
|
|
49
59
|
/** Direct the user to an external URL. */
|
|
50
|
-
url(
|
|
60
|
+
url(message: string, url: string, options?: ElicitUrlOptions): Promise<ElicitUrlResult>;
|
|
51
61
|
}
|
|
52
62
|
interface SampleOptions {
|
|
53
63
|
maxTokens?: number;
|
|
@@ -86,6 +96,14 @@ interface ToolContext {
|
|
|
86
96
|
roots: () => Promise<RootInfo[]>;
|
|
87
97
|
/** Request LLM inference from the client. */
|
|
88
98
|
sample: Sample;
|
|
99
|
+
/** Create a text response. Chainable. */
|
|
100
|
+
text(value: string): ToolResponse;
|
|
101
|
+
/** Create a JSON response. Chainable. */
|
|
102
|
+
json(value: unknown): ToolResponse;
|
|
103
|
+
/** Create an error response. Chainable. */
|
|
104
|
+
error(message: string): ToolResponse;
|
|
105
|
+
/** Create an image response. Chainable. */
|
|
106
|
+
image(data: string, mimeType: string): ToolResponse;
|
|
89
107
|
}
|
|
90
108
|
interface ToolInfo {
|
|
91
109
|
name: string;
|
|
@@ -98,16 +116,16 @@ interface ToolMiddleware {
|
|
|
98
116
|
/** Called when a tool is registered. Return false to hide the tool initially. */
|
|
99
117
|
onRegister?(tool: ToolInfo): boolean | undefined;
|
|
100
118
|
/** Called when a tool is invoked. Must call next() to continue the chain. */
|
|
101
|
-
onCall?(
|
|
119
|
+
onCall?(c: ToolContext, next: () => Promise<CallToolResult>): Promise<CallToolResult>;
|
|
102
120
|
/** Called after the handler returns. Runs in reverse middleware order. */
|
|
103
|
-
onResult?(result: CallToolResult,
|
|
121
|
+
onResult?(result: CallToolResult, c: ToolContext): CallToolResult | Promise<CallToolResult>;
|
|
104
122
|
}
|
|
105
123
|
type InferInput<T> = T extends z.ZodTypeAny ? z.output<T> : Record<string, unknown>;
|
|
106
124
|
interface ToolConfig<TInput = unknown> {
|
|
107
125
|
description?: string;
|
|
108
126
|
input?: TInput;
|
|
109
127
|
}
|
|
110
|
-
type ToolHandler<TInput = unknown> = (args: InferInput<TInput>,
|
|
128
|
+
type ToolHandler<TInput = unknown> = (args: InferInput<TInput>, c: ToolContext) => CallToolResult | Promise<CallToolResult>;
|
|
111
129
|
/** @experimental */
|
|
112
130
|
interface TaskConfig<TInput = unknown> {
|
|
113
131
|
description?: string;
|
|
@@ -125,7 +143,7 @@ interface TaskContext extends ToolContext {
|
|
|
125
143
|
task: TaskControl;
|
|
126
144
|
}
|
|
127
145
|
/** @experimental */
|
|
128
|
-
type TaskHandler<TInput = unknown> = (args: InferInput<TInput>,
|
|
146
|
+
type TaskHandler<TInput = unknown> = (args: InferInput<TInput>, c: TaskContext) => CallToolResult | Promise<CallToolResult>;
|
|
129
147
|
interface ResourceConfig {
|
|
130
148
|
name: string;
|
|
131
149
|
description?: string;
|
|
@@ -143,7 +161,7 @@ interface ResourceContext {
|
|
|
143
161
|
/** Query client-provided filesystem roots. */
|
|
144
162
|
roots: () => Promise<RootInfo[]>;
|
|
145
163
|
}
|
|
146
|
-
type ResourceHandler = (uri: string,
|
|
164
|
+
type ResourceHandler = (uri: string, c: ResourceContext) => ResourceContent | Promise<ResourceContent>;
|
|
147
165
|
interface HttpAdapterOptions {
|
|
148
166
|
/** Disable session management. Default: false. */
|
|
149
167
|
sessionless?: boolean;
|
|
@@ -151,6 +169,8 @@ interface HttpAdapterOptions {
|
|
|
151
169
|
sessionIdGenerator?: () => string;
|
|
152
170
|
/** Return JSON instead of SSE streams. Default: false. */
|
|
153
171
|
enableJsonResponse?: boolean;
|
|
172
|
+
/** Called on each HTTP request after session is resolved. Use to inject auth headers into sessions. */
|
|
173
|
+
onRequest?: (req: Request, sessionId: string, session: Session) => void | Promise<void>;
|
|
154
174
|
}
|
|
155
175
|
interface MCPServer {
|
|
156
176
|
/** Register a global middleware applied to all subsequently registered tools. */
|
|
@@ -171,6 +191,10 @@ interface MCPServer {
|
|
|
171
191
|
stdio(): Promise<void>;
|
|
172
192
|
/** Start HTTP transport. Returns a Web Standard request handler. */
|
|
173
193
|
http(options?: HttpAdapterOptions): (req: Request) => Promise<Response>;
|
|
194
|
+
/** Access a session by ID (for external HTTP callback routes). Stateful mode only. */
|
|
195
|
+
session(sessionId: string): Session;
|
|
196
|
+
/** Complete a pending URL elicitation (called from external HTTP callback). */
|
|
197
|
+
completeElicitation(elicitationId: string): void;
|
|
174
198
|
}
|
|
175
199
|
|
|
176
|
-
export type
|
|
200
|
+
export { type Elicit as E, type HttpAdapterOptions as H, type MCPServer as M, type ResourceConfig as R, type Sample as S, type TaskConfig as T, type ElicitFormResult as a, type ElicitUrlOptions as b, type ElicitUrlResult as c, type ResourceContent as d, type ResourceContext as e, type ResourceHandler as f, type RootInfo as g, type SampleOptions as h, type SampleRawParams as i, type SampleRawResult as j, type ServerInfo as k, type Session as l, type TaskContext as m, type TaskControl as n, type TaskHandler as o, type ToolConfig as p, type ToolContext as q, type ToolHandler as r, type ToolInfo as s, type ToolMiddleware as t, type ToolResponse as u, error as v, image as w, json as x, text as y };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lynq/lynq",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Lightweight MCP server framework. Tool visibility control through middleware.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -27,6 +27,58 @@
|
|
|
27
27
|
"./test": {
|
|
28
28
|
"types": "./dist/test.d.ts",
|
|
29
29
|
"import": "./dist/test.mjs"
|
|
30
|
+
},
|
|
31
|
+
"./guard": {
|
|
32
|
+
"types": "./dist/middleware/guard.d.ts",
|
|
33
|
+
"import": "./dist/middleware/guard.mjs"
|
|
34
|
+
},
|
|
35
|
+
"./logger": {
|
|
36
|
+
"types": "./dist/middleware/logger.d.ts",
|
|
37
|
+
"import": "./dist/middleware/logger.mjs"
|
|
38
|
+
},
|
|
39
|
+
"./rate-limit": {
|
|
40
|
+
"types": "./dist/middleware/rate-limit.d.ts",
|
|
41
|
+
"import": "./dist/middleware/rate-limit.mjs"
|
|
42
|
+
},
|
|
43
|
+
"./truncate": {
|
|
44
|
+
"types": "./dist/middleware/truncate.d.ts",
|
|
45
|
+
"import": "./dist/middleware/truncate.mjs"
|
|
46
|
+
},
|
|
47
|
+
"./combine": {
|
|
48
|
+
"types": "./dist/middleware/combine.d.ts",
|
|
49
|
+
"import": "./dist/middleware/combine.mjs"
|
|
50
|
+
},
|
|
51
|
+
"./credentials": {
|
|
52
|
+
"types": "./dist/middleware/credentials.d.ts",
|
|
53
|
+
"import": "./dist/middleware/credentials.mjs"
|
|
54
|
+
},
|
|
55
|
+
"./url-action": {
|
|
56
|
+
"types": "./dist/middleware/url-action.d.ts",
|
|
57
|
+
"import": "./dist/middleware/url-action.mjs"
|
|
58
|
+
},
|
|
59
|
+
"./oauth": {
|
|
60
|
+
"types": "./dist/middleware/oauth.d.ts",
|
|
61
|
+
"import": "./dist/middleware/oauth.mjs"
|
|
62
|
+
},
|
|
63
|
+
"./payment": {
|
|
64
|
+
"types": "./dist/middleware/payment.d.ts",
|
|
65
|
+
"import": "./dist/middleware/payment.mjs"
|
|
66
|
+
},
|
|
67
|
+
"./bearer": {
|
|
68
|
+
"types": "./dist/middleware/bearer.d.ts",
|
|
69
|
+
"import": "./dist/middleware/bearer.mjs"
|
|
70
|
+
},
|
|
71
|
+
"./jwt": {
|
|
72
|
+
"types": "./dist/middleware/jwt.d.ts",
|
|
73
|
+
"import": "./dist/middleware/jwt.mjs"
|
|
74
|
+
},
|
|
75
|
+
"./github-oauth": {
|
|
76
|
+
"types": "./dist/middleware/github-oauth.d.ts",
|
|
77
|
+
"import": "./dist/middleware/github-oauth.mjs"
|
|
78
|
+
},
|
|
79
|
+
"./google-oauth": {
|
|
80
|
+
"types": "./dist/middleware/google-oauth.d.ts",
|
|
81
|
+
"import": "./dist/middleware/google-oauth.mjs"
|
|
30
82
|
}
|
|
31
83
|
},
|
|
32
84
|
"files": [
|
|
@@ -46,12 +98,15 @@
|
|
|
46
98
|
"docs:preview": "vitepress preview docs",
|
|
47
99
|
"prepublishOnly": "pnpm build"
|
|
48
100
|
},
|
|
101
|
+
"dependencies": {
|
|
102
|
+
"@modelcontextprotocol/sdk": "^1.27.0"
|
|
103
|
+
},
|
|
49
104
|
"devDependencies": {
|
|
50
105
|
"@biomejs/biome": "^1.9.0",
|
|
51
|
-
"@modelcontextprotocol/sdk": "^1.27.0",
|
|
52
106
|
"@types/express": "^5.0.6",
|
|
53
107
|
"express": "^5.2.1",
|
|
54
108
|
"hono": "^4.12.5",
|
|
109
|
+
"jose": "^6.2.1",
|
|
55
110
|
"tsup": "^8.0.0",
|
|
56
111
|
"typedoc": "^0.28.17",
|
|
57
112
|
"typedoc-plugin-markdown": "^4.10.0",
|
|
@@ -61,9 +116,9 @@
|
|
|
61
116
|
"zod": "^3.24.0"
|
|
62
117
|
},
|
|
63
118
|
"peerDependencies": {
|
|
64
|
-
"@modelcontextprotocol/sdk": "^1.27.0",
|
|
65
119
|
"express": "^5.0.0",
|
|
66
120
|
"hono": "^4.0.0",
|
|
121
|
+
"jose": "^6.0.0",
|
|
67
122
|
"zod": "^3.0.0"
|
|
68
123
|
},
|
|
69
124
|
"peerDependenciesMeta": {
|
|
@@ -75,6 +130,9 @@
|
|
|
75
130
|
},
|
|
76
131
|
"express": {
|
|
77
132
|
"optional": true
|
|
133
|
+
},
|
|
134
|
+
"jose": {
|
|
135
|
+
"optional": true
|
|
78
136
|
}
|
|
79
137
|
},
|
|
80
138
|
"publishConfig": {
|