@softure-ai/mcp-access 0.5.0 → 0.6.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/CHANGELOG.md +9 -0
- package/README.md +50 -0
- package/dist/index.js +1 -1
- package/dist/server/endpoint.d.ts +8 -1
- package/dist/server/endpoint.d.ts.map +1 -1
- package/dist/server/endpoint.js +54 -7
- package/dist/server/endpoint.js.map +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/request-diagnostics.d.ts +59 -0
- package/dist/server/request-diagnostics.d.ts.map +1 -0
- package/dist/server/request-diagnostics.js +84 -0
- package/dist/server/request-diagnostics.js.map +1 -0
- package/module.json +1 -1
- package/package.json +1 -1
- package/src/index.ts +1 -1
- package/src/server/endpoint.ts +73 -6
- package/src/server/index.ts +1 -0
- package/src/server/request-diagnostics.ts +130 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,15 @@ Newest first. Each version lists what changed for an app that uses `@softure-ai/
|
|
|
4
4
|
production, the version gets a line `verified in: <app>@<commit>` ([docs/05](../../docs/05-adoption-playbook.md),
|
|
5
5
|
"Definition of done"). Versions before the first one below are described in their GitHub Releases (`mcp-access@x.y.z`).
|
|
6
6
|
|
|
7
|
+
## 0.6.0
|
|
8
|
+
|
|
9
|
+
- Request diagnostics (#1066): `createMcpEndpoint({ diagnostics })` (and so `createMcpRoute`), off by default. `true`
|
|
10
|
+
logs one `console.info` line per request, a function receives each `McpRequestDiagnostic` instead: the JSON-RPC
|
|
11
|
+
method, the tool name of a `tools/call`, the session state (`none`, `current`, `stale` with the version it carries,
|
|
12
|
+
`not_issued`, `unchecked`), the served tool list version, whether a session id was issued, the status, and on
|
|
13
|
+
`initialize` the client's `clientInfo` and protocol version. Never a token, body, argument value, session id or
|
|
14
|
+
user identity. The README says what hosted clients do with a changed tool list. Migrate: nothing.
|
|
15
|
+
|
|
7
16
|
## 0.5.0
|
|
8
17
|
|
|
9
18
|
- Sessions that follow the tool list (#1055): `createMcpEndpoint` answers `initialize` with an `Mcp-Session-Id` that
|
package/README.md
CHANGED
|
@@ -210,6 +210,54 @@ the tool list (#1055):
|
|
|
210
210
|
factory and throws unless a session opened under `before` is renewed for every access level whose list changed (and
|
|
211
211
|
kept for the others).
|
|
212
212
|
|
|
213
|
+
### Request diagnostics
|
|
214
|
+
|
|
215
|
+
When a client shows a tool list that the server no longer serves, the question is what the client sends. Turn the
|
|
216
|
+
diagnostics on for a test session, for example behind an env flag of the app:
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
// app/api/mcp/route.ts
|
|
220
|
+
export const POST = createMcpRoute({ createServer, diagnostics: process.env.MCP_DIAGNOSTICS === "1" });
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
- `true` logs one `console.info` line per request, `@softure-ai/mcp-access: mcp request {...}`; a function
|
|
224
|
+
(`diagnostics: (entry) => ...`) receives each `McpRequestDiagnostic` instead, for the app's own logger.
|
|
225
|
+
- An entry holds `httpMethod`, the JSON-RPC `method` (`"batch"` for an array), the `tool` of a `tools/call`,
|
|
226
|
+
`session` (`none`, `current`, `stale`, `not_issued` for an id the endpoint never issued, `unchecked` when it was not
|
|
227
|
+
checked), `sessionVersion` (the version a stale session carries), the served `toolListVersion`, `sessionIssued`,
|
|
228
|
+
the answer `status`, and on `initialize` the `client` (`clientInfo` name and version) and `protocolVersion`.
|
|
229
|
+
- Never in an entry: the token, the body, argument values, the session id or the user's identity. Client text is
|
|
230
|
+
cut to 128 characters and stripped of control characters.
|
|
231
|
+
|
|
232
|
+
Reading a test session: an `initialize` with `sessionIssued: true` followed by `tools/list` in `session: "current"`
|
|
233
|
+
is a client that follows the version. A `stale` 404 followed by no `initialize` is a client that ignores session
|
|
234
|
+
renewal. Only `tools/call` lines after a release, with `session: "none"` and no `tools/list`, is a client that serves the
|
|
235
|
+
model its own cached list.
|
|
236
|
+
|
|
237
|
+
### What hosted clients do with a changed tool list
|
|
238
|
+
|
|
239
|
+
Public reports up to 2026-11 show that the Claude apps (claude.ai custom connectors, the desktop and mobile apps)
|
|
240
|
+
keep a tool list cache on their side that nothing the server sends reliably refreshes: not a new server version
|
|
241
|
+
(#877), not session renewal (#1055), not `notifications/tools/list_changed`
|
|
242
|
+
([claude-ai-mcp#137](https://github.com/anthropics/claude-ai-mcp/issues/137),
|
|
243
|
+
[claude-ai-mcp#1182](https://github.com/anthropics/claude-ai-mcp/issues/1182),
|
|
244
|
+
[claude-code#38324](https://github.com/anthropics/claude-code/issues/38324),
|
|
245
|
+
[claude-code#88172](https://github.com/anthropics/claude-code/issues/88172)). The server can re-initialize correctly
|
|
246
|
+
while the model still sees the old schemas. What refreshed it differs by surface and over time:
|
|
247
|
+
|
|
248
|
+
- claude.ai web: a new conversation; when that is not enough, removing the connector and adding it again.
|
|
249
|
+
- Claude desktop and mobile apps: disconnect and reconnect in Settings → Connectors, otherwise remove and re-add the
|
|
250
|
+
connector; on the desktop app, quitting and relaunching the app.
|
|
251
|
+
- Claude Code: the cache is keyed by the server name
|
|
252
|
+
([claude-code#40025](https://github.com/anthropics/claude-code/issues/40025)); restart, or rename the server
|
|
253
|
+
entry.
|
|
254
|
+
|
|
255
|
+
What the server can do: keep #877 and #1055 on (a client that follows the protocol re-initializes and re-lists after the
|
|
256
|
+
404), and accept old input while clients catch up (a new field optional, a removed field
|
|
257
|
+
still parsed) so a stale schema degrades instead of failing. Renaming the server or the connector forces a new cache
|
|
258
|
+
entry, at the cost of every user reconnecting, so it is a last resort. Tell users after a release that changed a tool
|
|
259
|
+
schema: start a new conversation, and if the old tools are still shown, remove and re-add the connector.
|
|
260
|
+
|
|
213
261
|
### Strict tool input
|
|
214
262
|
|
|
215
263
|
zod objects strip unknown keys, so a call with a misspelt field (`notes` for `note`) or a field of a newer tool list
|
|
@@ -923,6 +971,8 @@ to `@softure-ai/privacy` (`privacy` flags on):
|
|
|
923
971
|
app that wants `jwks_uri` adds it through `oauth.metadata` and serves the empty set itself).
|
|
924
972
|
- Only `S256` PKCE and the `authorization_code` and `refresh_token` grants.
|
|
925
973
|
- Write access is per token, not per tool; finer scopes would be a new option.
|
|
974
|
+
- A hosted client's own tool list cache cannot be refreshed from the server (see "What hosted clients do with a
|
|
975
|
+
changed tool list"); the version and the session renewal help only clients that re-list.
|
|
926
976
|
- The MCP endpoint's rate limit is per client address, not per token (API tokens are counted per token as well).
|
|
927
977
|
- One API token kind per app (one prefix); the `kind` column takes more kinds without a migration of the rows.
|
|
928
978
|
- `responseMode: "json"` drops mid-call notifications; a streaming tool would need a different mode. Long work is an
|
package/dist/index.js
CHANGED
|
@@ -45,7 +45,7 @@ export const API_TOKEN_RATE_LIMIT_BUCKETS = {
|
|
|
45
45
|
export const mcpAccess = defineModule({
|
|
46
46
|
manifest: {
|
|
47
47
|
id: MODULE_ID,
|
|
48
|
-
version: "0.
|
|
48
|
+
version: "0.6.0",
|
|
49
49
|
dependsOn: { security: "^0.2.0", auth: "^0.2.0", jobs: "^0.1.1?", ops: "^0.2.0?" },
|
|
50
50
|
dbSchema: "mcp",
|
|
51
51
|
tables: ["access_tokens", "oauth_clients", "oauth_authorization_codes", "oauth_grants", "oauth_registration_window", "used_confirmations", "operation_tasks"],
|
|
@@ -2,6 +2,7 @@ import { type McpServer, type Server } from "@modelcontextprotocol/server";
|
|
|
2
2
|
import type { McpServerIdentity } from "../contract.js";
|
|
3
3
|
import { MCP_READ_SCOPE, MCP_WRITE_SCOPE } from "./scopes.js";
|
|
4
4
|
import { type McpAccessContext } from "./tokens.js";
|
|
5
|
+
import { type McpRequestDiagnostics } from "./request-diagnostics.js";
|
|
5
6
|
export { MCP_READ_SCOPE, MCP_WRITE_SCOPE };
|
|
6
7
|
/** The security bucket the endpoint counts in; `MCP_RATE_LIMIT_BUCKETS` holds its default. */
|
|
7
8
|
export declare const MCP_RATE_LIMIT_BUCKET = "mcp";
|
|
@@ -22,6 +23,12 @@ export interface McpEndpointOptions {
|
|
|
22
23
|
* `toolListVersion` (`createMcpServerFactory`). Without either, the endpoint issues no session id.
|
|
23
24
|
*/
|
|
24
25
|
readonly toolListVersion?: ToolListVersionReader;
|
|
26
|
+
/**
|
|
27
|
+
* Request diagnostics (#1066), off by default: `true` logs one `console.info` line per request, a function receives
|
|
28
|
+
* each entry. An entry holds the JSON-RPC method, the tool name, the session state, the served tool list version,
|
|
29
|
+
* the status and the client's `clientInfo` on `initialize`; never a token, body, argument value or identity.
|
|
30
|
+
*/
|
|
31
|
+
readonly diagnostics?: McpRequestDiagnostics;
|
|
25
32
|
}
|
|
26
33
|
/** Serves one request to the MCP endpoint. */
|
|
27
34
|
export type McpEndpoint = (ctx: McpAccessContext, request: Request) => Promise<Response>;
|
|
@@ -31,5 +38,5 @@ export type McpEndpoint = (ctx: McpAccessContext, request: Request) => Promise<R
|
|
|
31
38
|
* (`responseMode: "json"`): a stream would add proxy buffering and timeouts for no tool that needs
|
|
32
39
|
* it, and mid-call notifications are dropped.
|
|
33
40
|
*/
|
|
34
|
-
export declare function createMcpEndpoint({ createServer, toolListVersion }: McpEndpointOptions): McpEndpoint;
|
|
41
|
+
export declare function createMcpEndpoint({ createServer, toolListVersion, diagnostics }: McpEndpointOptions): McpEndpoint;
|
|
35
42
|
//# sourceMappingURL=endpoint.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"endpoint.d.ts","sourceRoot":"","sources":["../../src/server/endpoint.ts"],"names":[],"mappings":"AAKA,OAAO,EAML,KAAK,SAAS,EACd,KAAK,MAAM,EACZ,MAAM,8BAA8B,CAAC;AAGtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGxD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAWvE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC;AAE3C,8FAA8F;AAC9F,eAAO,MAAM,qBAAqB,QAAQ,CAAC;AAE3C,6FAA6F;AAC7F,eAAO,MAAM,qBAAqB,QAAc,CAAC;AAOjD,mGAAmG;AACnG,MAAM,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,iBAAiB,KAAK,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,MAAM,CAAC,CAAC;AAEjH,iGAAiG;AACjG,MAAM,MAAM,qBAAqB,GAAG,CAAC,QAAQ,EAAE,iBAAiB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAErF,qHAAqH;AACrH,MAAM,WAAW,yBAA0B,SAAQ,gBAAgB;IACjE,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC;CACjD;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,YAAY,EAAE,gBAAgB,GAAG,yBAAyB,CAAC;IACpE;;;OAGG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"endpoint.d.ts","sourceRoot":"","sources":["../../src/server/endpoint.ts"],"names":[],"mappings":"AAKA,OAAO,EAML,KAAK,SAAS,EACd,KAAK,MAAM,EACZ,MAAM,8BAA8B,CAAC;AAGtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGxD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAWvE,OAAO,EAML,KAAK,qBAAqB,EAE3B,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC;AAE3C,8FAA8F;AAC9F,eAAO,MAAM,qBAAqB,QAAQ,CAAC;AAE3C,6FAA6F;AAC7F,eAAO,MAAM,qBAAqB,QAAc,CAAC;AAOjD,mGAAmG;AACnG,MAAM,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,iBAAiB,KAAK,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,MAAM,CAAC,CAAC;AAEjH,iGAAiG;AACjG,MAAM,MAAM,qBAAqB,GAAG,CAAC,QAAQ,EAAE,iBAAiB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAErF,qHAAqH;AACrH,MAAM,WAAW,yBAA0B,SAAQ,gBAAgB;IACjE,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC;CACjD;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,YAAY,EAAE,gBAAgB,GAAG,yBAAyB,CAAC;IACpE;;;OAGG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,qBAAqB,CAAC;IACjD;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,qBAAqB,CAAC;CAC9C;AAUD,8CAA8C;AAC9C,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEzF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,EAAE,kBAAkB,GAAG,WAAW,CAmFjH"}
|
package/dist/server/endpoint.js
CHANGED
|
@@ -10,8 +10,9 @@ import { getProtectedResourceMetadataUrl, isOAuthEnabled } from "./oauth-http.js
|
|
|
10
10
|
import { resolveMcpOrigins } from "./origins.js";
|
|
11
11
|
import { MCP_READ_SCOPE, MCP_WRITE_SCOPE } from "./scopes.js";
|
|
12
12
|
import { verifyAccessToken } from "./tokens.js";
|
|
13
|
-
import { createSessionRenewalResponse, createToolListSessionId, isInitializeRequest, isToolListSessionCurrent, MCP_SESSION_ID_HEADER, rewriteInitializeAnswer, } from "./tool-list-session.js";
|
|
13
|
+
import { createSessionRenewalResponse, createToolListSessionId, isInitializeRequest, isToolListSessionCurrent, MCP_SESSION_ID_HEADER, readToolListSessionVersion, rewriteInitializeAnswer, } from "./tool-list-session.js";
|
|
14
14
|
import { isWritingEnabled } from "./writes-switch.js";
|
|
15
|
+
import { createDiagnosticsSink, readJsonRpcSummary, sanitizeDiagnosticText, } from "./request-diagnostics.js";
|
|
15
16
|
export { MCP_READ_SCOPE, MCP_WRITE_SCOPE };
|
|
16
17
|
/** The security bucket the endpoint counts in; `MCP_RATE_LIMIT_BUCKETS` holds its default. */
|
|
17
18
|
export const MCP_RATE_LIMIT_BUCKET = "mcp";
|
|
@@ -27,14 +28,27 @@ const NO_STORE = { "cache-control": "no-store" };
|
|
|
27
28
|
* (`responseMode: "json"`): a stream would add proxy buffering and timeouts for no tool that needs
|
|
28
29
|
* it, and mid-call notifications are dropped.
|
|
29
30
|
*/
|
|
30
|
-
export function createMcpEndpoint({ createServer, toolListVersion }) {
|
|
31
|
+
export function createMcpEndpoint({ createServer, toolListVersion, diagnostics }) {
|
|
31
32
|
const readToolListVersion = toolListVersion ?? getFactoryToolListVersion(createServer);
|
|
33
|
+
const report = createDiagnosticsSink(diagnostics);
|
|
32
34
|
const handler = createMcpHandler((requestContext) => createServer(readIdentity(requestContext.authInfo)), {
|
|
33
35
|
responseMode: "json",
|
|
34
36
|
maxRequestBodySize: MAX_MCP_REQUEST_BYTES,
|
|
35
37
|
onerror: (error) => console.error(`@softure-ai/mcp-access: the MCP handler reported: ${errorLogLabel(error)}`),
|
|
36
38
|
});
|
|
37
39
|
return async (ctx, request) => {
|
|
40
|
+
if (report === undefined)
|
|
41
|
+
return serve(ctx, request, null);
|
|
42
|
+
const trace = { session: "unchecked", sessionVersion: null, toolListVersion: null, sessionIssued: false };
|
|
43
|
+
// Read before serving: the SDK consumes the body. Only the method, tool name and clientInfo are kept.
|
|
44
|
+
const summary = await readJsonRpcSummary(request, MAX_MCP_REQUEST_BYTES);
|
|
45
|
+
const response = await serve(ctx, request, trace);
|
|
46
|
+
report(createDiagnostic(request, summary, trace, response.status));
|
|
47
|
+
return response;
|
|
48
|
+
};
|
|
49
|
+
async function serve(ctx, request, trace) {
|
|
50
|
+
if (trace !== null && !request.headers.has(MCP_SESSION_ID_HEADER))
|
|
51
|
+
trace.session = "none";
|
|
38
52
|
assertRateLimitBucket(ctx);
|
|
39
53
|
const client = identifyClient(ctx, request.headers);
|
|
40
54
|
if (!client.ok)
|
|
@@ -55,14 +69,14 @@ export function createMcpEndpoint({ createServer, toolListVersion }) {
|
|
|
55
69
|
const authInfo = await authenticate(ctx, request);
|
|
56
70
|
if (authInfo instanceof Response)
|
|
57
71
|
return authInfo;
|
|
58
|
-
return serveInSession(request, authInfo);
|
|
59
|
-
}
|
|
72
|
+
return serveInSession(request, authInfo, trace);
|
|
73
|
+
}
|
|
60
74
|
/**
|
|
61
75
|
* Sessions tied to the tool list version (#1055): a session from another version (a release changed a tool, or the
|
|
62
76
|
* access level changed) answers 404, so the client initializes again and lists the tools again; `initialize` gets a
|
|
63
77
|
* new session id. A request without a session id is served as it always was.
|
|
64
78
|
*/
|
|
65
|
-
async function serveInSession(request, authInfo) {
|
|
79
|
+
async function serveInSession(request, authInfo, trace) {
|
|
66
80
|
const sessionId = request.headers.get(MCP_SESSION_ID_HEADER);
|
|
67
81
|
const isInitialize = sessionId === null && (await isInitializeRequest(request, MAX_MCP_REQUEST_BYTES));
|
|
68
82
|
if (readToolListVersion === undefined || (sessionId === null && !isInitialize)) {
|
|
@@ -79,12 +93,45 @@ export function createMcpEndpoint({ createServer, toolListVersion }) {
|
|
|
79
93
|
const response = await handler.fetch(request, { authInfo });
|
|
80
94
|
return isInitialize ? rewriteInitializeAnswer(response, null) : response;
|
|
81
95
|
}
|
|
96
|
+
if (trace !== null)
|
|
97
|
+
trace.toolListVersion = version;
|
|
82
98
|
if (sessionId !== null) {
|
|
83
|
-
|
|
99
|
+
if (isToolListSessionCurrent(sessionId, version)) {
|
|
100
|
+
if (trace !== null)
|
|
101
|
+
trace.session = "current";
|
|
102
|
+
return handler.fetch(request, { authInfo });
|
|
103
|
+
}
|
|
104
|
+
if (trace !== null)
|
|
105
|
+
recordRenewedSession(trace, sessionId);
|
|
106
|
+
return createSessionRenewalResponse();
|
|
84
107
|
}
|
|
85
|
-
|
|
108
|
+
const response = await rewriteInitializeAnswer(await handler.fetch(request, { authInfo }), createToolListSessionId(version));
|
|
109
|
+
if (trace !== null)
|
|
110
|
+
trace.sessionIssued = response.headers.has(MCP_SESSION_ID_HEADER);
|
|
111
|
+
return response;
|
|
86
112
|
}
|
|
87
113
|
}
|
|
114
|
+
/** A session answered 404: stale when the id carries a version, not issued by the endpoint otherwise. */
|
|
115
|
+
function recordRenewedSession(trace, sessionId) {
|
|
116
|
+
const sessionVersion = readToolListSessionVersion(sessionId);
|
|
117
|
+
trace.session = sessionVersion === null ? "not_issued" : "stale";
|
|
118
|
+
trace.sessionVersion = sessionVersion === null ? null : sanitizeDiagnosticText(sessionVersion);
|
|
119
|
+
}
|
|
120
|
+
/** The diagnostics entry of one served request. */
|
|
121
|
+
function createDiagnostic(request, summary, trace, status) {
|
|
122
|
+
return {
|
|
123
|
+
httpMethod: request.method,
|
|
124
|
+
method: summary.method,
|
|
125
|
+
tool: summary.tool,
|
|
126
|
+
session: trace.session,
|
|
127
|
+
sessionVersion: trace.sessionVersion,
|
|
128
|
+
toolListVersion: trace.toolListVersion,
|
|
129
|
+
sessionIssued: trace.sessionIssued,
|
|
130
|
+
status,
|
|
131
|
+
client: summary.client,
|
|
132
|
+
protocolVersion: summary.protocolVersion,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
88
135
|
/** The factory's own version reader, when it has one (`createMcpServerFactory`). */
|
|
89
136
|
function getFactoryToolListVersion(factory) {
|
|
90
137
|
return "toolListVersion" in factory && typeof factory.toolListVersion === "function" ? factory.toolListVersion : undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"endpoint.js","sourceRoot":"","sources":["../../src/server/endpoint.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,oGAAoG;AACpG,gGAAgG;AAChG,kGAAkG;AAClG,4BAA4B;AAC5B,OAAO,EACL,2BAA2B,EAC3B,gBAAgB,EAChB,UAAU,EACV,cAAc,GAIf,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE/E,OAAO,EAAE,+BAA+B,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAClF,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAyB,MAAM,aAAa,CAAC;AACvE,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,mBAAmB,EACnB,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"endpoint.js","sourceRoot":"","sources":["../../src/server/endpoint.ts"],"names":[],"mappings":"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"}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -22,5 +22,6 @@ export { registerServerInfoTool, SERVER_INFO_TOOL_NAME, type McpBuildInfo, type
|
|
|
22
22
|
export { toStrictToolInput, withStrictToolInput, type RenamedFields, type StrictToolInputMessages, type StrictToolInputOptions } from "./strict-input.js";
|
|
23
23
|
export { DEFAULT_TOOL_LIST_RELEASE, describeToolList, fingerprintToolList, listServedTools, measureToolList, type MeasureToolListOptions, type RegisterTools, type ServedTool, type ToolListMeasurement, } from "./tool-list.js";
|
|
24
24
|
export { createToolListSessionId, isToolListSessionCurrent, MCP_SESSION_ID_HEADER, readToolListSessionVersion, } from "./tool-list-session.js";
|
|
25
|
+
export { type McpRequestDiagnostic, type McpRequestDiagnostics, type McpSessionState } from "./request-diagnostics.js";
|
|
25
26
|
export { toolError, toolResult, withToolErrors, type ToolCaller, type ToolCallHook, type ToolCallOutcome, type ToolCallRecord, type ToolErrorHints, type ToolErrorOptions, } from "./tools.js";
|
|
26
27
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
|
package/dist/server/index.js
CHANGED
|
@@ -23,5 +23,6 @@ export { registerServerInfoTool, SERVER_INFO_TOOL_NAME, } from "./server-info.js
|
|
|
23
23
|
export { toStrictToolInput, withStrictToolInput } from "./strict-input.js";
|
|
24
24
|
export { DEFAULT_TOOL_LIST_RELEASE, describeToolList, fingerprintToolList, listServedTools, measureToolList, } from "./tool-list.js";
|
|
25
25
|
export { createToolListSessionId, isToolListSessionCurrent, MCP_SESSION_ID_HEADER, readToolListSessionVersion, } from "./tool-list-session.js";
|
|
26
|
+
export {} from "./request-diagnostics.js";
|
|
26
27
|
export { toolError, toolResult, withToolErrors, } from "./tools.js";
|
|
27
28
|
//# sourceMappingURL=index.js.map
|
package/dist/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,+FAA+F;AAC/F,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACd,eAAe,GAMhB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAE,UAAU,EAAkD,MAAM,kBAAkB,CAAC;AAC1G,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,iBAAiB,EACjB,gCAAgC,EAChC,8BAA8B,EAC9B,sBAAsB,EACtB,eAAe,EACf,gBAAgB,GAMjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EACL,uBAAuB,EACvB,4BAA4B,EAC5B,wBAAwB,EACxB,+BAA+B,EAC/B,sBAAsB,GAGvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,yBAAyB,EACzB,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,GASjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,kCAAkC,EAClC,mBAAmB,EACnB,8BAA8B,EAC9B,cAAc,EACd,cAAc,EACd,4BAA4B,EAC5B,+BAA+B,EAC/B,gCAAgC,EAChC,2BAA2B,EAC3B,wBAAwB,EACxB,kBAAkB,EAClB,oBAAoB,EACpB,cAAc,EACd,qBAAqB,EACrB,2BAA2B,EAC3B,YAAY,EACZ,gCAAgC,EAChC,uBAAuB,EACvB,sBAAsB,EACtB,4BAA4B,GAK7B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAE,iBAAiB,EAA0C,MAAM,eAAe,CAAC;AACrI,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,uBAAuB,EAAyD,MAAM,uBAAuB,CAAC;AAC1L,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACrG,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,iBAAiB,EAAwB,MAAM,cAAc,CAAC;AACtI,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAA+B,MAAM,YAAY,CAAC;AAC9F,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,2BAA2B,GAE5B,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,GAOlB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,qBAAqB,EACrB,2BAA2B,EAC3B,qBAAqB,EACrB,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,eAAe,EACf,cAAc,GAMf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,sBAAsB,EAAgC,MAAM,qBAAqB,CAAC;AAC3F,OAAO,EACL,sBAAsB,EACtB,qBAAqB,GAMtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAiF,MAAM,mBAAmB,CAAC;AAC1J,OAAO,EACL,yBAAyB,EACzB,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,eAAe,GAKhB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,uBAAuB,EACvB,wBAAwB,EACxB,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAA+E,MAAM,0BAA0B,CAAC;AACvH,OAAO,EACL,SAAS,EACT,UAAU,EACV,cAAc,GAOf,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** How a request's `Mcp-Session-Id` relates to the tool list version (#1055). */
|
|
2
|
+
export type McpSessionState =
|
|
3
|
+
/** No session id came with the request. */
|
|
4
|
+
"none"
|
|
5
|
+
/** The session carries the current version and was served. */
|
|
6
|
+
| "current"
|
|
7
|
+
/** The session carries another version and was answered 404, so the client should initialize again. */
|
|
8
|
+
| "stale"
|
|
9
|
+
/** The session id is not one the endpoint issues; answered 404 like a stale one. */
|
|
10
|
+
| "not_issued"
|
|
11
|
+
/** A session id came, but it was not checked (refused before authentication, or no version to check against). */
|
|
12
|
+
| "unchecked";
|
|
13
|
+
/** One request as the diagnostics see it. */
|
|
14
|
+
export interface McpRequestDiagnostic {
|
|
15
|
+
/** The HTTP method. */
|
|
16
|
+
readonly httpMethod: string;
|
|
17
|
+
/** The JSON-RPC method, `"batch"` for an array, `null` when the body was not read or is not JSON-RPC. */
|
|
18
|
+
readonly method: string | null;
|
|
19
|
+
/** The tool name of a `tools/call`, otherwise `null`. */
|
|
20
|
+
readonly tool: string | null;
|
|
21
|
+
readonly session: McpSessionState;
|
|
22
|
+
/** The version a stale session carries, otherwise `null`. */
|
|
23
|
+
readonly sessionVersion: string | null;
|
|
24
|
+
/** The tool list version served to the identity, `null` when unknown (refused before authentication, no reader). */
|
|
25
|
+
readonly toolListVersion: string | null;
|
|
26
|
+
/** Whether the answer issued a new session id (a successful `initialize`). */
|
|
27
|
+
readonly sessionIssued: boolean;
|
|
28
|
+
/** The HTTP status of the answer. */
|
|
29
|
+
readonly status: number;
|
|
30
|
+
/** The client's `clientInfo` on `initialize`, otherwise `null`. */
|
|
31
|
+
readonly client: {
|
|
32
|
+
readonly name: string;
|
|
33
|
+
readonly version: string;
|
|
34
|
+
} | null;
|
|
35
|
+
/** The protocol version the client asked for on `initialize`, otherwise the `MCP-Protocol-Version` header, or `null`. */
|
|
36
|
+
readonly protocolVersion: string | null;
|
|
37
|
+
}
|
|
38
|
+
/** `true` logs one `console.info` line per request; a function receives each entry instead. */
|
|
39
|
+
export type McpRequestDiagnostics = boolean | ((entry: McpRequestDiagnostic) => void);
|
|
40
|
+
/** What the diagnostics read from a request body. */
|
|
41
|
+
export interface JsonRpcSummary {
|
|
42
|
+
readonly method: string | null;
|
|
43
|
+
readonly tool: string | null;
|
|
44
|
+
readonly client: {
|
|
45
|
+
readonly name: string;
|
|
46
|
+
readonly version: string;
|
|
47
|
+
} | null;
|
|
48
|
+
readonly protocolVersion: string | null;
|
|
49
|
+
}
|
|
50
|
+
/** Client-supplied text as it may be logged: control characters replaced, at most 128 characters. */
|
|
51
|
+
export declare function sanitizeDiagnosticText(value: string): string;
|
|
52
|
+
/**
|
|
53
|
+
* The method, tool name, `clientInfo` and protocol version of a request, read from a clone of its body. A body over
|
|
54
|
+
* `maxBytes` or one that is not JSON gives no method (the SDK answers it itself). Nothing else of the body is kept.
|
|
55
|
+
*/
|
|
56
|
+
export declare function readJsonRpcSummary(request: Request, maxBytes: number): Promise<JsonRpcSummary>;
|
|
57
|
+
/** The sink for the option, or `undefined` when diagnostics are off. A throwing sink is logged, never rethrown. */
|
|
58
|
+
export declare function createDiagnosticsSink(diagnostics: McpRequestDiagnostics | undefined): ((entry: McpRequestDiagnostic) => void) | undefined;
|
|
59
|
+
//# sourceMappingURL=request-diagnostics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-diagnostics.d.ts","sourceRoot":"","sources":["../../src/server/request-diagnostics.ts"],"names":[],"mappings":"AAMA,iFAAiF;AACjF,MAAM,MAAM,eAAe;AACzB,2CAA2C;AACzC,MAAM;AACR,8DAA8D;GAC5D,SAAS;AACX,uGAAuG;GACrG,OAAO;AACT,oFAAoF;GAClF,YAAY;AACd,iHAAiH;GAC/G,WAAW,CAAC;AAEhB,6CAA6C;AAC7C,MAAM,WAAW,oBAAoB;IACnC,uBAAuB;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,yGAAyG;IACzG,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,6DAA6D;IAC7D,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,oHAAoH;IACpH,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,8EAA8E;IAC9E,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,qCAAqC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,mEAAmE;IACnE,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC5E,yHAAyH;IACzH,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CACzC;AAED,+FAA+F;AAC/F,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,CAAC,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC,CAAC;AAEtF,qDAAqD;AACrD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC5E,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CACzC;AAMD,qGAAqG;AACrG,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAG5D;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAmCpG;AAED,mHAAmH;AACnH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,qBAAqB,GAAG,SAAS,GAAG,CAAC,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC,GAAG,SAAS,CAUzI"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// Opt-in request diagnostics for the MCP endpoint (#1066). A hosted client can keep a stale tool list although the
|
|
2
|
+
// server serves the current one, and nothing showed what the client actually sends. One entry per request says which
|
|
3
|
+
// JSON-RPC method came, in which session state, with which answer. No token, body, argument value, session id or
|
|
4
|
+
// user identity is ever part of an entry; client-supplied strings are cut and stripped of control characters.
|
|
5
|
+
import { errorLogLabel } from "@softure-ai/core";
|
|
6
|
+
const MAX_TEXT_LENGTH = 128;
|
|
7
|
+
const PROTOCOL_VERSION_HEADER = "mcp-protocol-version";
|
|
8
|
+
const EMPTY_SUMMARY = { method: null, tool: null, client: null, protocolVersion: null };
|
|
9
|
+
/** Client-supplied text as it may be logged: control characters replaced, at most 128 characters. */
|
|
10
|
+
export function sanitizeDiagnosticText(value) {
|
|
11
|
+
const clean = Array.from(value, (character) => (isControlCharacter(character) ? "?" : character)).join("");
|
|
12
|
+
return clean.length > MAX_TEXT_LENGTH ? `${clean.slice(0, MAX_TEXT_LENGTH)}…` : clean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The method, tool name, `clientInfo` and protocol version of a request, read from a clone of its body. A body over
|
|
16
|
+
* `maxBytes` or one that is not JSON gives no method (the SDK answers it itself). Nothing else of the body is kept.
|
|
17
|
+
*/
|
|
18
|
+
export async function readJsonRpcSummary(request, maxBytes) {
|
|
19
|
+
const header = request.headers.get(PROTOCOL_VERSION_HEADER);
|
|
20
|
+
const headerVersion = header === null ? null : sanitizeDiagnosticText(header);
|
|
21
|
+
const withHeader = { ...EMPTY_SUMMARY, protocolVersion: headerVersion };
|
|
22
|
+
if (request.method !== "POST")
|
|
23
|
+
return withHeader;
|
|
24
|
+
const length = Number(request.headers.get("content-length") ?? "0");
|
|
25
|
+
if (!Number.isFinite(length) || length > maxBytes)
|
|
26
|
+
return withHeader;
|
|
27
|
+
let body;
|
|
28
|
+
try {
|
|
29
|
+
const text = await request.clone().text();
|
|
30
|
+
if (text.length > maxBytes)
|
|
31
|
+
return withHeader;
|
|
32
|
+
body = JSON.parse(text);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Not JSON or no readable body: the SDK answers that itself; the entry just has no method.
|
|
36
|
+
return withHeader;
|
|
37
|
+
}
|
|
38
|
+
if (Array.isArray(body))
|
|
39
|
+
return { ...withHeader, method: "batch" };
|
|
40
|
+
if (!isRecord(body) || typeof body.method !== "string")
|
|
41
|
+
return withHeader;
|
|
42
|
+
const method = sanitizeDiagnosticText(body.method);
|
|
43
|
+
const params = isRecord(body.params) ? body.params : {};
|
|
44
|
+
if (body.method === "tools/call") {
|
|
45
|
+
return { ...withHeader, method, tool: typeof params.name === "string" ? sanitizeDiagnosticText(params.name) : null };
|
|
46
|
+
}
|
|
47
|
+
if (body.method !== "initialize")
|
|
48
|
+
return { ...withHeader, method };
|
|
49
|
+
const clientInfo = isRecord(params.clientInfo) ? params.clientInfo : null;
|
|
50
|
+
const client = clientInfo === null
|
|
51
|
+
? null
|
|
52
|
+
: {
|
|
53
|
+
name: typeof clientInfo.name === "string" ? sanitizeDiagnosticText(clientInfo.name) : "",
|
|
54
|
+
version: typeof clientInfo.version === "string" ? sanitizeDiagnosticText(clientInfo.version) : "",
|
|
55
|
+
};
|
|
56
|
+
const protocolVersion = typeof params.protocolVersion === "string" ? sanitizeDiagnosticText(params.protocolVersion) : headerVersion;
|
|
57
|
+
return { method, tool: null, client, protocolVersion };
|
|
58
|
+
}
|
|
59
|
+
/** The sink for the option, or `undefined` when diagnostics are off. A throwing sink is logged, never rethrown. */
|
|
60
|
+
export function createDiagnosticsSink(diagnostics) {
|
|
61
|
+
if (diagnostics === undefined || diagnostics === false)
|
|
62
|
+
return undefined;
|
|
63
|
+
const write = diagnostics === true ? logDiagnostic : diagnostics;
|
|
64
|
+
return (entry) => {
|
|
65
|
+
try {
|
|
66
|
+
write(entry);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
console.error(`@softure-ai/mcp-access: the request diagnostics sink failed: ${errorLogLabel(error)}`);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function logDiagnostic(entry) {
|
|
74
|
+
console.info(`@softure-ai/mcp-access: mcp request ${JSON.stringify(entry)}`);
|
|
75
|
+
}
|
|
76
|
+
/** C0 controls, DEL and C1 controls: anything that could break or forge a log line. */
|
|
77
|
+
function isControlCharacter(character) {
|
|
78
|
+
const code = character.codePointAt(0) ?? 0;
|
|
79
|
+
return code < 0x20 || (code >= 0x7f && code <= 0x9f);
|
|
80
|
+
}
|
|
81
|
+
function isRecord(value) {
|
|
82
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=request-diagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-diagnostics.js","sourceRoot":"","sources":["../../src/server/request-diagnostics.ts"],"names":[],"mappings":"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"}
|
package/module.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "mcp-access",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"dependsOn": { "security": "^0.2.0", "auth": "^0.2.0", "jobs": "^0.1.1?", "ops": "^0.2.0?" },
|
|
5
5
|
"dbSchema": "mcp",
|
|
6
6
|
"tables": ["access_tokens", "oauth_clients", "oauth_authorization_codes", "oauth_grants", "oauth_registration_window", "used_confirmations", "operation_tasks"],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softure-ai/mcp-access",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "SOFTURE AI MCP access module: hashed, scoped, expiring access tokens, a rate-limited Bearer endpoint around the app's MCP server factory, and a token page with client setup instructions for Next.js; tool result helpers with a safe error boundary, a stdio entry, a catalog parity check and the softure-mcp prune command.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/src/index.ts
CHANGED
|
@@ -51,7 +51,7 @@ export const API_TOKEN_RATE_LIMIT_BUCKETS = {
|
|
|
51
51
|
export const mcpAccess = defineModule({
|
|
52
52
|
manifest: {
|
|
53
53
|
id: MODULE_ID,
|
|
54
|
-
version: "0.
|
|
54
|
+
version: "0.6.0",
|
|
55
55
|
dependsOn: { security: "^0.2.0", auth: "^0.2.0", jobs: "^0.1.1?", ops: "^0.2.0?" },
|
|
56
56
|
dbSchema: "mcp",
|
|
57
57
|
tables: ["access_tokens", "oauth_clients", "oauth_authorization_codes", "oauth_grants", "oauth_registration_window", "used_confirmations", "operation_tasks"],
|
package/src/server/endpoint.ts
CHANGED
|
@@ -25,9 +25,19 @@ import {
|
|
|
25
25
|
isInitializeRequest,
|
|
26
26
|
isToolListSessionCurrent,
|
|
27
27
|
MCP_SESSION_ID_HEADER,
|
|
28
|
+
readToolListSessionVersion,
|
|
28
29
|
rewriteInitializeAnswer,
|
|
29
30
|
} from "./tool-list-session.js";
|
|
30
31
|
import { isWritingEnabled } from "./writes-switch.js";
|
|
32
|
+
import {
|
|
33
|
+
createDiagnosticsSink,
|
|
34
|
+
readJsonRpcSummary,
|
|
35
|
+
sanitizeDiagnosticText,
|
|
36
|
+
type JsonRpcSummary,
|
|
37
|
+
type McpRequestDiagnostic,
|
|
38
|
+
type McpRequestDiagnostics,
|
|
39
|
+
type McpSessionState,
|
|
40
|
+
} from "./request-diagnostics.js";
|
|
31
41
|
|
|
32
42
|
export { MCP_READ_SCOPE, MCP_WRITE_SCOPE };
|
|
33
43
|
|
|
@@ -60,6 +70,20 @@ export interface McpEndpointOptions {
|
|
|
60
70
|
* `toolListVersion` (`createMcpServerFactory`). Without either, the endpoint issues no session id.
|
|
61
71
|
*/
|
|
62
72
|
readonly toolListVersion?: ToolListVersionReader;
|
|
73
|
+
/**
|
|
74
|
+
* Request diagnostics (#1066), off by default: `true` logs one `console.info` line per request, a function receives
|
|
75
|
+
* each entry. An entry holds the JSON-RPC method, the tool name, the session state, the served tool list version,
|
|
76
|
+
* the status and the client's `clientInfo` on `initialize`; never a token, body, argument value or identity.
|
|
77
|
+
*/
|
|
78
|
+
readonly diagnostics?: McpRequestDiagnostics;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** What serving a request found out, for the diagnostics. */
|
|
82
|
+
interface SessionTrace {
|
|
83
|
+
session: McpSessionState;
|
|
84
|
+
sessionVersion: string | null;
|
|
85
|
+
toolListVersion: string | null;
|
|
86
|
+
sessionIssued: boolean;
|
|
63
87
|
}
|
|
64
88
|
|
|
65
89
|
/** Serves one request to the MCP endpoint. */
|
|
@@ -71,8 +95,9 @@ export type McpEndpoint = (ctx: McpAccessContext, request: Request) => Promise<R
|
|
|
71
95
|
* (`responseMode: "json"`): a stream would add proxy buffering and timeouts for no tool that needs
|
|
72
96
|
* it, and mid-call notifications are dropped.
|
|
73
97
|
*/
|
|
74
|
-
export function createMcpEndpoint({ createServer, toolListVersion }: McpEndpointOptions): McpEndpoint {
|
|
98
|
+
export function createMcpEndpoint({ createServer, toolListVersion, diagnostics }: McpEndpointOptions): McpEndpoint {
|
|
75
99
|
const readToolListVersion = toolListVersion ?? getFactoryToolListVersion(createServer);
|
|
100
|
+
const report = createDiagnosticsSink(diagnostics);
|
|
76
101
|
const handler = createMcpHandler(
|
|
77
102
|
(requestContext) => createServer(readIdentity(requestContext.authInfo)),
|
|
78
103
|
{
|
|
@@ -83,6 +108,17 @@ export function createMcpEndpoint({ createServer, toolListVersion }: McpEndpoint
|
|
|
83
108
|
);
|
|
84
109
|
|
|
85
110
|
return async (ctx, request) => {
|
|
111
|
+
if (report === undefined) return serve(ctx, request, null);
|
|
112
|
+
const trace: SessionTrace = { session: "unchecked", sessionVersion: null, toolListVersion: null, sessionIssued: false };
|
|
113
|
+
// Read before serving: the SDK consumes the body. Only the method, tool name and clientInfo are kept.
|
|
114
|
+
const summary = await readJsonRpcSummary(request, MAX_MCP_REQUEST_BYTES);
|
|
115
|
+
const response = await serve(ctx, request, trace);
|
|
116
|
+
report(createDiagnostic(request, summary, trace, response.status));
|
|
117
|
+
return response;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
async function serve(ctx: McpAccessContext, request: Request, trace: SessionTrace | null): Promise<Response> {
|
|
121
|
+
if (trace !== null && !request.headers.has(MCP_SESSION_ID_HEADER)) trace.session = "none";
|
|
86
122
|
assertRateLimitBucket(ctx);
|
|
87
123
|
const client = identifyClient(ctx, request.headers);
|
|
88
124
|
if (!client.ok) return Response.json({ error: "client_unidentified" }, { status: 400, headers: NO_STORE });
|
|
@@ -105,15 +141,15 @@ export function createMcpEndpoint({ createServer, toolListVersion }: McpEndpoint
|
|
|
105
141
|
|
|
106
142
|
const authInfo = await authenticate(ctx, request);
|
|
107
143
|
if (authInfo instanceof Response) return authInfo;
|
|
108
|
-
return serveInSession(request, authInfo);
|
|
109
|
-
}
|
|
144
|
+
return serveInSession(request, authInfo, trace);
|
|
145
|
+
}
|
|
110
146
|
|
|
111
147
|
/**
|
|
112
148
|
* Sessions tied to the tool list version (#1055): a session from another version (a release changed a tool, or the
|
|
113
149
|
* access level changed) answers 404, so the client initializes again and lists the tools again; `initialize` gets a
|
|
114
150
|
* new session id. A request without a session id is served as it always was.
|
|
115
151
|
*/
|
|
116
|
-
async function serveInSession(request: Request, authInfo: AuthInfo): Promise<Response> {
|
|
152
|
+
async function serveInSession(request: Request, authInfo: AuthInfo, trace: SessionTrace | null): Promise<Response> {
|
|
117
153
|
const sessionId = request.headers.get(MCP_SESSION_ID_HEADER);
|
|
118
154
|
const isInitialize = sessionId === null && (await isInitializeRequest(request, MAX_MCP_REQUEST_BYTES));
|
|
119
155
|
if (readToolListVersion === undefined || (sessionId === null && !isInitialize)) {
|
|
@@ -129,13 +165,44 @@ export function createMcpEndpoint({ createServer, toolListVersion }: McpEndpoint
|
|
|
129
165
|
const response = await handler.fetch(request, { authInfo });
|
|
130
166
|
return isInitialize ? rewriteInitializeAnswer(response, null) : response;
|
|
131
167
|
}
|
|
168
|
+
if (trace !== null) trace.toolListVersion = version;
|
|
132
169
|
if (sessionId !== null) {
|
|
133
|
-
|
|
170
|
+
if (isToolListSessionCurrent(sessionId, version)) {
|
|
171
|
+
if (trace !== null) trace.session = "current";
|
|
172
|
+
return handler.fetch(request, { authInfo });
|
|
173
|
+
}
|
|
174
|
+
if (trace !== null) recordRenewedSession(trace, sessionId);
|
|
175
|
+
return createSessionRenewalResponse();
|
|
134
176
|
}
|
|
135
|
-
|
|
177
|
+
const response = await rewriteInitializeAnswer(await handler.fetch(request, { authInfo }), createToolListSessionId(version));
|
|
178
|
+
if (trace !== null) trace.sessionIssued = response.headers.has(MCP_SESSION_ID_HEADER);
|
|
179
|
+
return response;
|
|
136
180
|
}
|
|
137
181
|
}
|
|
138
182
|
|
|
183
|
+
/** A session answered 404: stale when the id carries a version, not issued by the endpoint otherwise. */
|
|
184
|
+
function recordRenewedSession(trace: SessionTrace, sessionId: string): void {
|
|
185
|
+
const sessionVersion = readToolListSessionVersion(sessionId);
|
|
186
|
+
trace.session = sessionVersion === null ? "not_issued" : "stale";
|
|
187
|
+
trace.sessionVersion = sessionVersion === null ? null : sanitizeDiagnosticText(sessionVersion);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** The diagnostics entry of one served request. */
|
|
191
|
+
function createDiagnostic(request: Request, summary: JsonRpcSummary, trace: SessionTrace, status: number): McpRequestDiagnostic {
|
|
192
|
+
return {
|
|
193
|
+
httpMethod: request.method,
|
|
194
|
+
method: summary.method,
|
|
195
|
+
tool: summary.tool,
|
|
196
|
+
session: trace.session,
|
|
197
|
+
sessionVersion: trace.sessionVersion,
|
|
198
|
+
toolListVersion: trace.toolListVersion,
|
|
199
|
+
sessionIssued: trace.sessionIssued,
|
|
200
|
+
status,
|
|
201
|
+
client: summary.client,
|
|
202
|
+
protocolVersion: summary.protocolVersion,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
139
206
|
/** The factory's own version reader, when it has one (`createMcpServerFactory`). */
|
|
140
207
|
function getFactoryToolListVersion(factory: McpServerFactory | VersionedMcpServerFactory): ToolListVersionReader | undefined {
|
|
141
208
|
return "toolListVersion" in factory && typeof factory.toolListVersion === "function" ? factory.toolListVersion : undefined;
|
package/src/server/index.ts
CHANGED
|
@@ -163,6 +163,7 @@ export {
|
|
|
163
163
|
MCP_SESSION_ID_HEADER,
|
|
164
164
|
readToolListSessionVersion,
|
|
165
165
|
} from "./tool-list-session.js";
|
|
166
|
+
export { type McpRequestDiagnostic, type McpRequestDiagnostics, type McpSessionState } from "./request-diagnostics.js";
|
|
166
167
|
export {
|
|
167
168
|
toolError,
|
|
168
169
|
toolResult,
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// Opt-in request diagnostics for the MCP endpoint (#1066). A hosted client can keep a stale tool list although the
|
|
2
|
+
// server serves the current one, and nothing showed what the client actually sends. One entry per request says which
|
|
3
|
+
// JSON-RPC method came, in which session state, with which answer. No token, body, argument value, session id or
|
|
4
|
+
// user identity is ever part of an entry; client-supplied strings are cut and stripped of control characters.
|
|
5
|
+
import { errorLogLabel } from "@softure-ai/core";
|
|
6
|
+
|
|
7
|
+
/** How a request's `Mcp-Session-Id` relates to the tool list version (#1055). */
|
|
8
|
+
export type McpSessionState =
|
|
9
|
+
/** No session id came with the request. */
|
|
10
|
+
| "none"
|
|
11
|
+
/** The session carries the current version and was served. */
|
|
12
|
+
| "current"
|
|
13
|
+
/** The session carries another version and was answered 404, so the client should initialize again. */
|
|
14
|
+
| "stale"
|
|
15
|
+
/** The session id is not one the endpoint issues; answered 404 like a stale one. */
|
|
16
|
+
| "not_issued"
|
|
17
|
+
/** A session id came, but it was not checked (refused before authentication, or no version to check against). */
|
|
18
|
+
| "unchecked";
|
|
19
|
+
|
|
20
|
+
/** One request as the diagnostics see it. */
|
|
21
|
+
export interface McpRequestDiagnostic {
|
|
22
|
+
/** The HTTP method. */
|
|
23
|
+
readonly httpMethod: string;
|
|
24
|
+
/** The JSON-RPC method, `"batch"` for an array, `null` when the body was not read or is not JSON-RPC. */
|
|
25
|
+
readonly method: string | null;
|
|
26
|
+
/** The tool name of a `tools/call`, otherwise `null`. */
|
|
27
|
+
readonly tool: string | null;
|
|
28
|
+
readonly session: McpSessionState;
|
|
29
|
+
/** The version a stale session carries, otherwise `null`. */
|
|
30
|
+
readonly sessionVersion: string | null;
|
|
31
|
+
/** The tool list version served to the identity, `null` when unknown (refused before authentication, no reader). */
|
|
32
|
+
readonly toolListVersion: string | null;
|
|
33
|
+
/** Whether the answer issued a new session id (a successful `initialize`). */
|
|
34
|
+
readonly sessionIssued: boolean;
|
|
35
|
+
/** The HTTP status of the answer. */
|
|
36
|
+
readonly status: number;
|
|
37
|
+
/** The client's `clientInfo` on `initialize`, otherwise `null`. */
|
|
38
|
+
readonly client: { readonly name: string; readonly version: string } | null;
|
|
39
|
+
/** The protocol version the client asked for on `initialize`, otherwise the `MCP-Protocol-Version` header, or `null`. */
|
|
40
|
+
readonly protocolVersion: string | null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** `true` logs one `console.info` line per request; a function receives each entry instead. */
|
|
44
|
+
export type McpRequestDiagnostics = boolean | ((entry: McpRequestDiagnostic) => void);
|
|
45
|
+
|
|
46
|
+
/** What the diagnostics read from a request body. */
|
|
47
|
+
export interface JsonRpcSummary {
|
|
48
|
+
readonly method: string | null;
|
|
49
|
+
readonly tool: string | null;
|
|
50
|
+
readonly client: { readonly name: string; readonly version: string } | null;
|
|
51
|
+
readonly protocolVersion: string | null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const MAX_TEXT_LENGTH = 128;
|
|
55
|
+
const PROTOCOL_VERSION_HEADER = "mcp-protocol-version";
|
|
56
|
+
const EMPTY_SUMMARY: JsonRpcSummary = { method: null, tool: null, client: null, protocolVersion: null };
|
|
57
|
+
|
|
58
|
+
/** Client-supplied text as it may be logged: control characters replaced, at most 128 characters. */
|
|
59
|
+
export function sanitizeDiagnosticText(value: string): string {
|
|
60
|
+
const clean = Array.from(value, (character) => (isControlCharacter(character) ? "?" : character)).join("");
|
|
61
|
+
return clean.length > MAX_TEXT_LENGTH ? `${clean.slice(0, MAX_TEXT_LENGTH)}…` : clean;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The method, tool name, `clientInfo` and protocol version of a request, read from a clone of its body. A body over
|
|
66
|
+
* `maxBytes` or one that is not JSON gives no method (the SDK answers it itself). Nothing else of the body is kept.
|
|
67
|
+
*/
|
|
68
|
+
export async function readJsonRpcSummary(request: Request, maxBytes: number): Promise<JsonRpcSummary> {
|
|
69
|
+
const header = request.headers.get(PROTOCOL_VERSION_HEADER);
|
|
70
|
+
const headerVersion = header === null ? null : sanitizeDiagnosticText(header);
|
|
71
|
+
const withHeader = { ...EMPTY_SUMMARY, protocolVersion: headerVersion };
|
|
72
|
+
if (request.method !== "POST") return withHeader;
|
|
73
|
+
const length = Number(request.headers.get("content-length") ?? "0");
|
|
74
|
+
if (!Number.isFinite(length) || length > maxBytes) return withHeader;
|
|
75
|
+
let body: unknown;
|
|
76
|
+
try {
|
|
77
|
+
const text = await request.clone().text();
|
|
78
|
+
if (text.length > maxBytes) return withHeader;
|
|
79
|
+
body = JSON.parse(text);
|
|
80
|
+
} catch {
|
|
81
|
+
// Not JSON or no readable body: the SDK answers that itself; the entry just has no method.
|
|
82
|
+
return withHeader;
|
|
83
|
+
}
|
|
84
|
+
if (Array.isArray(body)) return { ...withHeader, method: "batch" };
|
|
85
|
+
if (!isRecord(body) || typeof body.method !== "string") return withHeader;
|
|
86
|
+
|
|
87
|
+
const method = sanitizeDiagnosticText(body.method);
|
|
88
|
+
const params = isRecord(body.params) ? body.params : {};
|
|
89
|
+
if (body.method === "tools/call") {
|
|
90
|
+
return { ...withHeader, method, tool: typeof params.name === "string" ? sanitizeDiagnosticText(params.name) : null };
|
|
91
|
+
}
|
|
92
|
+
if (body.method !== "initialize") return { ...withHeader, method };
|
|
93
|
+
const clientInfo = isRecord(params.clientInfo) ? params.clientInfo : null;
|
|
94
|
+
const client =
|
|
95
|
+
clientInfo === null
|
|
96
|
+
? null
|
|
97
|
+
: {
|
|
98
|
+
name: typeof clientInfo.name === "string" ? sanitizeDiagnosticText(clientInfo.name) : "",
|
|
99
|
+
version: typeof clientInfo.version === "string" ? sanitizeDiagnosticText(clientInfo.version) : "",
|
|
100
|
+
};
|
|
101
|
+
const protocolVersion = typeof params.protocolVersion === "string" ? sanitizeDiagnosticText(params.protocolVersion) : headerVersion;
|
|
102
|
+
return { method, tool: null, client, protocolVersion };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** The sink for the option, or `undefined` when diagnostics are off. A throwing sink is logged, never rethrown. */
|
|
106
|
+
export function createDiagnosticsSink(diagnostics: McpRequestDiagnostics | undefined): ((entry: McpRequestDiagnostic) => void) | undefined {
|
|
107
|
+
if (diagnostics === undefined || diagnostics === false) return undefined;
|
|
108
|
+
const write = diagnostics === true ? logDiagnostic : diagnostics;
|
|
109
|
+
return (entry) => {
|
|
110
|
+
try {
|
|
111
|
+
write(entry);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error(`@softure-ai/mcp-access: the request diagnostics sink failed: ${errorLogLabel(error)}`);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function logDiagnostic(entry: McpRequestDiagnostic): void {
|
|
119
|
+
console.info(`@softure-ai/mcp-access: mcp request ${JSON.stringify(entry)}`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** C0 controls, DEL and C1 controls: anything that could break or forge a log line. */
|
|
123
|
+
function isControlCharacter(character: string): boolean {
|
|
124
|
+
const code = character.codePointAt(0) ?? 0;
|
|
125
|
+
return code < 0x20 || (code >= 0x7f && code <= 0x9f);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
129
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
130
|
+
}
|