mcp-usage-control-mcp 1.0.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/LICENSE +201 -0
- package/README.md +135 -0
- package/dist/flow-store-conformance.d.ts +42 -0
- package/dist/flow-store-conformance.d.ts.map +1 -0
- package/dist/flow-store-conformance.js +178 -0
- package/dist/flow-store-conformance.js.map +1 -0
- package/dist/index.d.ts +178 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +525 -0
- package/dist/index.js.map +1 -0
- package/package.json +71 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import type { ServerContext } from '@modelcontextprotocol/server';
|
|
2
|
+
import { type Principal, type UsageControl, type UsageLease, type UsageLeaseResumeState } from 'mcp-usage-control';
|
|
3
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
4
|
+
export interface ProtectToolOptions<TArgs, TResult> {
|
|
5
|
+
control: UsageControl;
|
|
6
|
+
tool: string;
|
|
7
|
+
/**
|
|
8
|
+
* Set to true when the MCP tool has no input schema.
|
|
9
|
+
*
|
|
10
|
+
* The SDK's TypeScript callback type is `(ctx)` for no-input tools, while
|
|
11
|
+
* some server dispatch paths invoke the callback at runtime as `({}, ctx)`.
|
|
12
|
+
* An empty object is indistinguishable from valid args for an empty input
|
|
13
|
+
* schema, so this adapter requires an explicit mode instead of guessing.
|
|
14
|
+
*/
|
|
15
|
+
noInput?: boolean;
|
|
16
|
+
principal(ctx: ServerContext): MaybePromise<Principal>;
|
|
17
|
+
operationId(args: TArgs, ctx: ServerContext): MaybePromise<string>;
|
|
18
|
+
/** Disable only when the application renews the lease itself. Defaults to true. */
|
|
19
|
+
leaseHeartbeat?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Best-effort notification that automatic lease renewal became acknowledgement-ambiguous,
|
|
22
|
+
* or that a later renewal confirmed the lease again. The callback is advisory only: it
|
|
23
|
+
* never changes authoritative accounting state and callback failures are ignored.
|
|
24
|
+
*/
|
|
25
|
+
onLeaseRenewalState?(event: LeaseRenewalStateEvent): MaybePromise<void>;
|
|
26
|
+
successUnits?(input: {
|
|
27
|
+
result: TResult;
|
|
28
|
+
args: TArgs;
|
|
29
|
+
ctx: ServerContext;
|
|
30
|
+
lease: UsageLease;
|
|
31
|
+
}): MaybePromise<number>;
|
|
32
|
+
toolErrorUnits?(input: {
|
|
33
|
+
result: TResult;
|
|
34
|
+
args: TArgs;
|
|
35
|
+
ctx: ServerContext;
|
|
36
|
+
lease: UsageLease;
|
|
37
|
+
}): MaybePromise<number>;
|
|
38
|
+
errorUnits?(input: {
|
|
39
|
+
error: unknown;
|
|
40
|
+
args: TArgs;
|
|
41
|
+
ctx: ServerContext;
|
|
42
|
+
lease: UsageLease;
|
|
43
|
+
}): MaybePromise<number>;
|
|
44
|
+
}
|
|
45
|
+
export type LeaseRenewalStateEvent = {
|
|
46
|
+
status: 'uncertain';
|
|
47
|
+
lease: UsageLease;
|
|
48
|
+
error: unknown;
|
|
49
|
+
} | {
|
|
50
|
+
status: 'confirmed';
|
|
51
|
+
lease: UsageLease;
|
|
52
|
+
};
|
|
53
|
+
export type NoInputProtectToolOptions<TResult> = ProtectToolOptions<undefined, TResult> & {
|
|
54
|
+
noInput: true;
|
|
55
|
+
};
|
|
56
|
+
export type InputProtectToolOptions<TArgs, TResult> = ProtectToolOptions<TArgs, TResult> & {
|
|
57
|
+
noInput?: false;
|
|
58
|
+
};
|
|
59
|
+
export type NoInputProtectedToolHandler<TResult> = (ctx: ServerContext) => Promise<TResult>;
|
|
60
|
+
export type InputProtectedToolHandler<TArgs, TResult> = (args: TArgs, ctx: ServerContext) => Promise<TResult>;
|
|
61
|
+
/** Decoded payload expected from the SDK requestState verification hook. */
|
|
62
|
+
export interface McpUsageRequestStatePayload {
|
|
63
|
+
mcpUsageControl: 1;
|
|
64
|
+
flowId: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Binding checked atomically before a suspended flow is consumed.
|
|
68
|
+
* The args hash prevents a retry from changing the original tool arguments.
|
|
69
|
+
*/
|
|
70
|
+
export interface McpUsageFlowBinding {
|
|
71
|
+
principalId: string;
|
|
72
|
+
tenantId?: string;
|
|
73
|
+
tool: string;
|
|
74
|
+
argsHash: string;
|
|
75
|
+
}
|
|
76
|
+
/** Serializable trusted server-side state for one suspended MCP usage flow. */
|
|
77
|
+
export interface McpUsageFlowRecord {
|
|
78
|
+
flowId: string;
|
|
79
|
+
binding: McpUsageFlowBinding;
|
|
80
|
+
lease: UsageLeaseResumeState;
|
|
81
|
+
/** First handler entry is round 0; the first retry is round 1. */
|
|
82
|
+
round: number;
|
|
83
|
+
expiresAt: number;
|
|
84
|
+
/** Original handler-authored requestState, retained server-side rather than trusted from the client. */
|
|
85
|
+
applicationRequestState?: string;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Server-side suspended-flow storage.
|
|
89
|
+
*
|
|
90
|
+
* `consume()` MUST atomically compare `binding`, reject expired state using the
|
|
91
|
+
* store's authoritative time domain, and remove the flow only when it matches
|
|
92
|
+
* and remains valid. A mismatched or expired caller must receive undefined
|
|
93
|
+
* without consuming a legitimate live flow. A successfully returned record is
|
|
94
|
+
* authoritative proof that suspended-flow expiry passed; callers MUST NOT
|
|
95
|
+
* reinterpret that result using an unrelated application-host clock. This
|
|
96
|
+
* one-time consume prevents concurrent retry re-entry.
|
|
97
|
+
*/
|
|
98
|
+
export interface McpUsageFlowStore {
|
|
99
|
+
suspend(record: McpUsageFlowRecord): MaybePromise<void>;
|
|
100
|
+
consume(flowId: string, binding: McpUsageFlowBinding): MaybePromise<McpUsageFlowRecord | undefined>;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Process-local flow store for tests and single-process servers.
|
|
104
|
+
*
|
|
105
|
+
* Instantiate it outside a `createMcpHandler` per-request factory. Distributed
|
|
106
|
+
* or horizontally scaled servers should provide a durable store with atomic
|
|
107
|
+
* compare-and-consume semantics instead.
|
|
108
|
+
*/
|
|
109
|
+
export declare class MemoryMcpUsageFlowStore implements McpUsageFlowStore {
|
|
110
|
+
private readonly flows;
|
|
111
|
+
suspend(record: McpUsageFlowRecord): void;
|
|
112
|
+
consume(flowId: string, binding: McpUsageFlowBinding): McpUsageFlowRecord | undefined;
|
|
113
|
+
private pruneExpired;
|
|
114
|
+
}
|
|
115
|
+
export interface McpUsageRequestStateMinter {
|
|
116
|
+
/**
|
|
117
|
+
* Mint an integrity-protected requestState value for the client round-trip.
|
|
118
|
+
* Use the same codec whose `verify` hook is configured on the MCP server.
|
|
119
|
+
*/
|
|
120
|
+
mint(payload: McpUsageRequestStatePayload, ctx: ServerContext): MaybePromise<string>;
|
|
121
|
+
}
|
|
122
|
+
export interface McpUsageFlowContext {
|
|
123
|
+
/** First handler entry is 0; each successful resume increments it by one. */
|
|
124
|
+
readonly round: number;
|
|
125
|
+
/** Stable logical operation ID from the first round. */
|
|
126
|
+
readonly operationId: string;
|
|
127
|
+
/**
|
|
128
|
+
* Handler-authored requestState captured from the prior input_required result.
|
|
129
|
+
* It came from trusted server-side flow storage; the wrapper-owned wire
|
|
130
|
+
* requestState is not exposed here.
|
|
131
|
+
*/
|
|
132
|
+
readonly applicationRequestState?: string;
|
|
133
|
+
}
|
|
134
|
+
export interface ProtectMultiRoundToolOptions<TArgs, TResult> extends ProtectToolOptions<TArgs, TResult> {
|
|
135
|
+
flowStore: McpUsageFlowStore;
|
|
136
|
+
requestState: McpUsageRequestStateMinter;
|
|
137
|
+
/** Explicit human/input suspension lease duration. Required to avoid an accidental unbounded hold. */
|
|
138
|
+
suspendTtlMs: number;
|
|
139
|
+
/** Maximum number of resumed rounds. Defaults to 8. */
|
|
140
|
+
maxRounds?: number;
|
|
141
|
+
/** Test/custom ID generator. Defaults to a cryptographically random ID. */
|
|
142
|
+
flowId?: () => MaybePromise<string>;
|
|
143
|
+
}
|
|
144
|
+
export type NoInputProtectMultiRoundToolOptions<TResult> = ProtectMultiRoundToolOptions<undefined, TResult> & {
|
|
145
|
+
noInput: true;
|
|
146
|
+
};
|
|
147
|
+
export type InputProtectMultiRoundToolOptions<TArgs, TResult> = ProtectMultiRoundToolOptions<TArgs, TResult> & {
|
|
148
|
+
noInput?: false;
|
|
149
|
+
};
|
|
150
|
+
export declare class UsageSettlementError extends Error {
|
|
151
|
+
readonly settlementError: unknown;
|
|
152
|
+
readonly executionError?: unknown | undefined;
|
|
153
|
+
constructor(message: string, settlementError: unknown, executionError?: unknown | undefined);
|
|
154
|
+
}
|
|
155
|
+
export declare class UsageClassificationError extends Error {
|
|
156
|
+
readonly classificationError: unknown;
|
|
157
|
+
readonly executionError?: unknown | undefined;
|
|
158
|
+
constructor(message: string, classificationError: unknown, executionError?: unknown | undefined);
|
|
159
|
+
}
|
|
160
|
+
export declare class UnsupportedMcpUsageFlowError extends Error {
|
|
161
|
+
constructor(message: string);
|
|
162
|
+
}
|
|
163
|
+
export declare class McpUsageResumeError extends Error {
|
|
164
|
+
constructor(message: string);
|
|
165
|
+
}
|
|
166
|
+
export declare class McpUsageRoundsExceededError extends Error {
|
|
167
|
+
constructor(message: string);
|
|
168
|
+
}
|
|
169
|
+
/** No-input-schema overload. `noInput: true` is required. */
|
|
170
|
+
export declare function protectTool<TResult>(options: NoInputProtectToolOptions<TResult>, handler: (args: undefined, ctx: ServerContext) => MaybePromise<TResult>): NoInputProtectedToolHandler<TResult>;
|
|
171
|
+
/** Input-schema overload. `noInput` must be omitted or false. */
|
|
172
|
+
export declare function protectTool<TArgs, TResult>(options: InputProtectToolOptions<TArgs, TResult>, handler: (args: TArgs, ctx: ServerContext) => MaybePromise<TResult>): InputProtectedToolHandler<TArgs, TResult>;
|
|
173
|
+
/** No-input-schema multi-round overload. */
|
|
174
|
+
export declare function protectMultiRoundTool<TResult>(options: NoInputProtectMultiRoundToolOptions<TResult>, handler: (args: undefined, ctx: ServerContext, flow: McpUsageFlowContext) => MaybePromise<TResult>): NoInputProtectedToolHandler<TResult>;
|
|
175
|
+
/** Input-schema multi-round overload. */
|
|
176
|
+
export declare function protectMultiRoundTool<TArgs, TResult>(options: InputProtectMultiRoundToolOptions<TArgs, TResult>, handler: (args: TArgs, ctx: ServerContext, flow: McpUsageFlowContext) => MaybePromise<TResult>): InputProtectedToolHandler<TArgs, TResult>;
|
|
177
|
+
export {};
|
|
178
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|