@behavior-os/mcp-server 0.0.0-stage → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ # MIT License
2
+
3
+ Copyright (c) 2026 Ilvan Joaquim
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,2 @@
1
+ export * from './server.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from './server.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC"}
@@ -0,0 +1,64 @@
1
+ /** Default ceiling: 300 calls per tool per minute (5/s average). */ export declare const DEFAULT_RATE_LIMIT_MAX_CALLS = 300;
2
+ export declare const DEFAULT_RATE_LIMIT_WINDOW_MS = 60000;
3
+ export interface RateLimitConfig {
4
+ /** Bucket capacity and number of calls allowed per `windowMs`. */
5
+ maxCalls: number;
6
+ /** Refill window in milliseconds. */
7
+ windowMs: number;
8
+ /** When true, `check()` always allows the call. */
9
+ disabled: boolean;
10
+ }
11
+ export interface RateLimitDecision {
12
+ allowed: boolean;
13
+ /** Configured bucket capacity. */
14
+ limit: number;
15
+ /** Whole calls left in the bucket after this decision. */
16
+ remaining: number;
17
+ /** Milliseconds until one token is available; 0 when allowed. */
18
+ retryAfterMs: number;
19
+ }
20
+ /**
21
+ * Per-tool token bucket.
22
+ *
23
+ * MCP runs over stdio in a single process, so the bucket is intentionally
24
+ * in-process: it throttles a runaway or looping agent, it is not a distributed
25
+ * quota and does not replace authentication or authorization. Each tool has its
26
+ * own bucket, so one noisy read-only tool cannot starve a governance call.
27
+ */
28
+ export declare class ToolRateLimiter {
29
+ private readonly buckets;
30
+ private readonly maxCalls;
31
+ private readonly windowMs;
32
+ private readonly disabled;
33
+ constructor(config: RateLimitConfig);
34
+ get limit(): number;
35
+ get window(): number;
36
+ /**
37
+ * Consume one token for `toolName`. `now` is injectable so tests can prove
38
+ * refill behavior without sleeping.
39
+ */
40
+ check(toolName: string, now?: number): RateLimitDecision;
41
+ /** Forget one tool's history, or every tool when called with no argument. */
42
+ reset(toolName?: string): void;
43
+ private refillPerMs;
44
+ }
45
+ export interface ParsedRateLimitConfig {
46
+ config: RateLimitConfig;
47
+ warnings: string[];
48
+ }
49
+ /**
50
+ * Read the optional environment overrides. Missing variables keep the secure
51
+ * defaults; malformed values are reported and replaced by the default instead
52
+ * of silently disabling the limiter.
53
+ */
54
+ export declare function rateLimitConfigFromEnv(env?: NodeJS.ProcessEnv): ParsedRateLimitConfig;
55
+ /**
56
+ * Wrap a registered tool callback with the shared limiter. The check runs
57
+ * before the handler, so a throttled call does no engine work and returns a
58
+ * normal MCP error result (the client sees `isError: true`, not a crash).
59
+ *
60
+ * The wrapper is generic over the callback's function type, so the MCP SDK's
61
+ * per-tool argument inference is preserved.
62
+ */
63
+ export declare function withRateLimit<F extends (...args: never[]) => unknown>(toolName: string, callback: F, limiter: ToolRateLimiter): F;
64
+ //# sourceMappingURL=rate-limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AAAA,oEAAoE,CAAC,eAAO,MAAM,4BAA4B,MAAM,CAAC;AACrH,eAAO,MAAM,4BAA4B,QAAS,CAAC;AAEnD,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,YAAY,EAAE,MAAM,CAAC;CACtB;AAOD;;;;;;;GAOG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6B;IACrD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;gBAEvB,MAAM,EAAE,eAAe;IAYnC,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED;;;OAGG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,iBAAiB;IAiCpE,6EAA6E;IAC7E,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAQ9B,OAAO,CAAC,WAAW;CAGpB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,eAAe,CAAC;IACxB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAiBD;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,qBAAqB,CAiBvB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,OAAO,EACnE,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,CAAC,EACX,OAAO,EAAE,eAAe,GACvB,CAAC,CAgBH"}
@@ -0,0 +1,127 @@
1
+ /** Default ceiling: 300 calls per tool per minute (5/s average). */ export const DEFAULT_RATE_LIMIT_MAX_CALLS = 300;
2
+ export const DEFAULT_RATE_LIMIT_WINDOW_MS = 60_000;
3
+ /**
4
+ * Per-tool token bucket.
5
+ *
6
+ * MCP runs over stdio in a single process, so the bucket is intentionally
7
+ * in-process: it throttles a runaway or looping agent, it is not a distributed
8
+ * quota and does not replace authentication or authorization. Each tool has its
9
+ * own bucket, so one noisy read-only tool cannot starve a governance call.
10
+ */
11
+ export class ToolRateLimiter {
12
+ buckets = new Map();
13
+ maxCalls;
14
+ windowMs;
15
+ disabled;
16
+ constructor(config) {
17
+ if (!Number.isFinite(config.maxCalls) || config.maxCalls < 1) {
18
+ throw new RangeError('rate limit maxCalls must be >= 1');
19
+ }
20
+ if (!Number.isFinite(config.windowMs) || config.windowMs < 1) {
21
+ throw new RangeError('rate limit windowMs must be >= 1');
22
+ }
23
+ this.maxCalls = Math.floor(config.maxCalls);
24
+ this.windowMs = Math.floor(config.windowMs);
25
+ this.disabled = config.disabled;
26
+ }
27
+ get limit() {
28
+ return this.maxCalls;
29
+ }
30
+ get window() {
31
+ return this.windowMs;
32
+ }
33
+ /**
34
+ * Consume one token for `toolName`. `now` is injectable so tests can prove
35
+ * refill behavior without sleeping.
36
+ */
37
+ check(toolName, now = Date.now()) {
38
+ if (this.disabled) {
39
+ return { allowed: true, limit: this.maxCalls, remaining: this.maxCalls, retryAfterMs: 0 };
40
+ }
41
+ let bucket = this.buckets.get(toolName);
42
+ if (!bucket) {
43
+ bucket = { tokens: this.maxCalls, updatedAt: now };
44
+ this.buckets.set(toolName, bucket);
45
+ }
46
+ else {
47
+ const elapsed = Math.max(0, now - bucket.updatedAt);
48
+ bucket.tokens = Math.min(this.maxCalls, bucket.tokens + elapsed * this.refillPerMs());
49
+ bucket.updatedAt = now;
50
+ }
51
+ if (bucket.tokens >= 1) {
52
+ bucket.tokens -= 1;
53
+ return {
54
+ allowed: true,
55
+ limit: this.maxCalls,
56
+ remaining: Math.floor(bucket.tokens),
57
+ retryAfterMs: 0,
58
+ };
59
+ }
60
+ return {
61
+ allowed: false,
62
+ limit: this.maxCalls,
63
+ remaining: 0,
64
+ retryAfterMs: Math.max(1, Math.ceil((1 - bucket.tokens) / this.refillPerMs())),
65
+ };
66
+ }
67
+ /** Forget one tool's history, or every tool when called with no argument. */
68
+ reset(toolName) {
69
+ if (toolName === undefined) {
70
+ this.buckets.clear();
71
+ }
72
+ else {
73
+ this.buckets.delete(toolName);
74
+ }
75
+ }
76
+ refillPerMs() {
77
+ return this.maxCalls / this.windowMs;
78
+ }
79
+ }
80
+ function positiveInteger(raw, fallback, name, warnings) {
81
+ if (raw === undefined || raw.trim() === '')
82
+ return fallback;
83
+ const parsed = Number(raw);
84
+ if (!Number.isInteger(parsed) || parsed < 1) {
85
+ warnings.push(`${name}="${raw}" is invalid; using ${fallback}`);
86
+ return fallback;
87
+ }
88
+ return parsed;
89
+ }
90
+ /**
91
+ * Read the optional environment overrides. Missing variables keep the secure
92
+ * defaults; malformed values are reported and replaced by the default instead
93
+ * of silently disabling the limiter.
94
+ */
95
+ export function rateLimitConfigFromEnv(env = process.env) {
96
+ const warnings = [];
97
+ const maxCalls = positiveInteger(env.BEHAVIOROS_MCP_RATE_LIMIT_MAX, DEFAULT_RATE_LIMIT_MAX_CALLS, 'BEHAVIOROS_MCP_RATE_LIMIT_MAX', warnings);
98
+ const windowMs = positiveInteger(env.BEHAVIOROS_MCP_RATE_LIMIT_WINDOW_MS, DEFAULT_RATE_LIMIT_WINDOW_MS, 'BEHAVIOROS_MCP_RATE_LIMIT_WINDOW_MS', warnings);
99
+ const disabled = env.BEHAVIOROS_MCP_RATE_LIMIT_DISABLED === 'true';
100
+ return { config: { maxCalls, windowMs, disabled }, warnings };
101
+ }
102
+ /**
103
+ * Wrap a registered tool callback with the shared limiter. The check runs
104
+ * before the handler, so a throttled call does no engine work and returns a
105
+ * normal MCP error result (the client sees `isError: true`, not a crash).
106
+ *
107
+ * The wrapper is generic over the callback's function type, so the MCP SDK's
108
+ * per-tool argument inference is preserved.
109
+ */
110
+ export function withRateLimit(toolName, callback, limiter) {
111
+ return (async (...args) => {
112
+ const decision = limiter.check(toolName);
113
+ if (!decision.allowed) {
114
+ return {
115
+ content: [
116
+ {
117
+ type: 'text',
118
+ text: `Rate limit exceeded for ${toolName}: retry after ${decision.retryAfterMs} ms (limit ${decision.limit} calls per ${limiter.window} ms).`,
119
+ },
120
+ ],
121
+ isError: true,
122
+ };
123
+ }
124
+ return callback(...args);
125
+ });
126
+ }
127
+ //# sourceMappingURL=rate-limit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { z } from 'zod';
4
+ import { ToolRateLimiter } from './rate-limit.js';
5
+ export declare const server: McpServer;
6
+ export declare const toolRateLimiter: ToolRateLimiter;
7
+ /**
8
+ * Exported for tests that need a fresh server instance (e.g. InMemoryTransport
9
+ * contracts). Each call creates a new McpServer so the singleton does not get
10
+ * re-connected across tests.
11
+ */
12
+ export declare function createServer(): McpServer;
13
+ /**
14
+ * Canonical structural shape of a vote, shared by every tool that accepts one
15
+ * (`bos_decide`, `bos_evolution`, `bos_apply_code_fixes`, `bos_code_edit`).
16
+ * Kept in one place so a malformed vote is rejected at the tool boundary
17
+ * instead of reaching the decision engine.
18
+ */
19
+ export declare const voteSchema: z.ZodObject<{
20
+ voterId: z.ZodString;
21
+ choice: z.ZodEnum<{
22
+ approve: "approve";
23
+ reject: "reject";
24
+ abstain: "abstain";
25
+ }>;
26
+ weight: z.ZodOptional<z.ZodNumber>;
27
+ reason: z.ZodOptional<z.ZodString>;
28
+ }, z.core.$strip>;
29
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AAiBA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAA0B,eAAe,EAAiB,MAAM,iBAAiB,CAAC;AAkCzF,eAAO,MAAM,MAAM,WAGjB,CAAC;AAYH,eAAO,MAAM,eAAe,iBAA8C,CAAC;AAS3E;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,SAAS,CAExC;AAED;;;;;GAKG;AACH,eAAO,MAAM,UAAU;;;;;;;;;iBAKrB,CAAC"}