@elnora-ai/mcp-server 0.1.1 → 0.2.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 +2 -2
- package/dist/auth/clients-store.d.ts +13 -0
- package/dist/auth/clients-store.d.ts.map +1 -0
- package/dist/auth/clients-store.js +35 -0
- package/dist/auth/clients-store.js.map +1 -0
- package/dist/auth/provider.d.ts +55 -0
- package/dist/auth/provider.d.ts.map +1 -0
- package/dist/auth/provider.js +234 -0
- package/dist/auth/provider.js.map +1 -0
- package/dist/constants.d.ts +7 -2
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +18 -4
- package/dist/constants.js.map +1 -1
- package/dist/index.js +81 -13
- package/dist/index.js.map +1 -1
- package/dist/middleware/cors.d.ts +11 -0
- package/dist/middleware/cors.d.ts.map +1 -0
- package/dist/middleware/cors.js +42 -0
- package/dist/middleware/cors.js.map +1 -0
- package/dist/middleware/rate-limiter.d.ts +13 -0
- package/dist/middleware/rate-limiter.d.ts.map +1 -0
- package/dist/middleware/rate-limiter.js +59 -0
- package/dist/middleware/rate-limiter.js.map +1 -0
- package/dist/middleware/tool-logging.d.ts +11 -0
- package/dist/middleware/tool-logging.d.ts.map +1 -0
- package/dist/middleware/tool-logging.js +40 -0
- package/dist/middleware/tool-logging.js.map +1 -0
- package/dist/server.d.ts +6 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +10 -6
- package/dist/server.js.map +1 -1
- package/dist/services/elnora-api-client.d.ts +0 -2
- package/dist/services/elnora-api-client.d.ts.map +1 -1
- package/dist/services/elnora-api-client.js +0 -4
- package/dist/services/elnora-api-client.js.map +1 -1
- package/dist/tools/files.d.ts +2 -1
- package/dist/tools/files.d.ts.map +1 -1
- package/dist/tools/files.js +8 -7
- package/dist/tools/files.js.map +1 -1
- package/dist/tools/messages.d.ts +2 -1
- package/dist/tools/messages.d.ts.map +1 -1
- package/dist/tools/messages.js +5 -4
- package/dist/tools/messages.js.map +1 -1
- package/dist/tools/protocols.d.ts +2 -1
- package/dist/tools/protocols.d.ts.map +1 -1
- package/dist/tools/protocols.js +4 -3
- package/dist/tools/protocols.js.map +1 -1
- package/dist/tools/scope-guard.d.ts +19 -0
- package/dist/tools/scope-guard.d.ts.map +1 -0
- package/dist/tools/scope-guard.js +33 -0
- package/dist/tools/scope-guard.js.map +1 -0
- package/dist/tools/tasks.d.ts +2 -1
- package/dist/tools/tasks.d.ts.map +1 -1
- package/dist/tools/tasks.js +8 -7
- package/dist/tools/tasks.js.map +1 -1
- package/dist/tools/with-guard.d.ts +19 -0
- package/dist/tools/with-guard.d.ts.map +1 -0
- package/dist/tools/with-guard.js +32 -0
- package/dist/tools/with-guard.js.map +1 -0
- package/dist/types.d.ts +32 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/dist/auth/middleware.d.ts +0 -12
- package/dist/auth/middleware.d.ts.map +0 -1
- package/dist/auth/middleware.js +0 -40
- package/dist/auth/middleware.js.map +0 -1
- package/dist/auth/protected-resource.d.ts +0 -4
- package/dist/auth/protected-resource.d.ts.map +0 -1
- package/dist/auth/protected-resource.js +0 -19
- package/dist/auth/protected-resource.js.map +0 -1
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CORS middleware restricting origins to the Elnora platform domain.
|
|
3
|
+
* CoSAI MCP-T7: Prevent cross-origin data leaks and CORS policy bypass.
|
|
4
|
+
*
|
|
5
|
+
* MCP clients communicate via direct HTTP (not browser), so CORS is primarily
|
|
6
|
+
* defense-in-depth against browser-based attacks targeting the MCP endpoint.
|
|
7
|
+
*/
|
|
8
|
+
export function corsMiddleware(config) {
|
|
9
|
+
const publicOrigin = new URL(config.publicUrl).origin;
|
|
10
|
+
const platformOrigin = config.loginUrl ? new URL(config.loginUrl).origin : null;
|
|
11
|
+
// Allowed origins: the MCP server itself and the platform
|
|
12
|
+
const allowedOrigins = new Set([publicOrigin]);
|
|
13
|
+
if (platformOrigin)
|
|
14
|
+
allowedOrigins.add(platformOrigin);
|
|
15
|
+
// Allow configuring additional origins via env var (comma-separated)
|
|
16
|
+
const extraOrigins = process.env.CORS_ALLOWED_ORIGINS;
|
|
17
|
+
if (extraOrigins) {
|
|
18
|
+
for (const origin of extraOrigins.split(",")) {
|
|
19
|
+
const trimmed = origin.trim();
|
|
20
|
+
if (trimmed)
|
|
21
|
+
allowedOrigins.add(trimmed);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return (req, res, next) => {
|
|
25
|
+
const origin = req.headers.origin;
|
|
26
|
+
if (origin && allowedOrigins.has(origin)) {
|
|
27
|
+
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
28
|
+
res.setHeader("Vary", "Origin");
|
|
29
|
+
}
|
|
30
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
31
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, MCP-Protocol-Version");
|
|
32
|
+
res.setHeader("Access-Control-Max-Age", "86400");
|
|
33
|
+
// Never expose tokens or auth headers to browsers
|
|
34
|
+
res.setHeader("Access-Control-Expose-Headers", "WWW-Authenticate");
|
|
35
|
+
if (req.method === "OPTIONS") {
|
|
36
|
+
res.status(204).end();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
next();
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=cors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.js","sourceRoot":"","sources":["../../src/middleware/cors.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,MAAoB;IACjD,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC;IACtD,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;IAEhF,0DAA0D;IAC1D,MAAM,cAAc,GAAG,IAAI,GAAG,CAAS,CAAC,YAAY,CAAC,CAAC,CAAC;IACvD,IAAI,cAAc;QAAE,cAAc,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAEvD,qEAAqE;IACrE,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;IACtD,IAAI,YAAY,EAAE,CAAC;QACjB,KAAK,MAAM,MAAM,IAAI,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7C,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;YAC9B,IAAI,OAAO;gBAAE,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACxB,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;QAElC,IAAI,MAAM,IAAI,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACzC,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;YACrD,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAClC,CAAC;QAED,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,oBAAoB,CAAC,CAAC;QACpE,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,mDAAmD,CAAC,CAAC;QACnG,GAAG,CAAC,SAAS,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;QACjD,kDAAkD;QAClD,GAAG,CAAC,SAAS,CAAC,+BAA+B,EAAE,kBAAkB,CAAC,CAAC;QAEnE,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC7B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;YACtB,OAAO;QACT,CAAC;QAED,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { RequestHandler } from "express";
|
|
2
|
+
/**
|
|
3
|
+
* Simple in-memory rate limiter for the /mcp endpoint.
|
|
4
|
+
* CoSAI MCP-T10: Prevent resource exhaustion and denial-of-wallet attacks.
|
|
5
|
+
*
|
|
6
|
+
* Limits by client IP (or Authorization header hash for authenticated requests).
|
|
7
|
+
* Default: 60 requests per minute per client.
|
|
8
|
+
*/
|
|
9
|
+
export declare function mcpRateLimiter(opts?: {
|
|
10
|
+
maxRequests?: number;
|
|
11
|
+
windowMs?: number;
|
|
12
|
+
}): RequestHandler;
|
|
13
|
+
//# sourceMappingURL=rate-limiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/middleware/rate-limiter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEzC;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,cAAc,CAiDjG"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple in-memory rate limiter for the /mcp endpoint.
|
|
3
|
+
* CoSAI MCP-T10: Prevent resource exhaustion and denial-of-wallet attacks.
|
|
4
|
+
*
|
|
5
|
+
* Limits by client IP (or Authorization header hash for authenticated requests).
|
|
6
|
+
* Default: 60 requests per minute per client.
|
|
7
|
+
*/
|
|
8
|
+
export function mcpRateLimiter(opts) {
|
|
9
|
+
const maxRequests = opts?.maxRequests ?? 60;
|
|
10
|
+
const windowMs = opts?.windowMs ?? 60_000;
|
|
11
|
+
const hits = new Map();
|
|
12
|
+
// Periodic cleanup to prevent memory leak
|
|
13
|
+
setInterval(() => {
|
|
14
|
+
const now = Date.now();
|
|
15
|
+
for (const [key, record] of hits) {
|
|
16
|
+
if (record.resetAt <= now)
|
|
17
|
+
hits.delete(key);
|
|
18
|
+
}
|
|
19
|
+
}, windowMs).unref();
|
|
20
|
+
return (req, res, next) => {
|
|
21
|
+
// Key by bearer token (if present) or IP
|
|
22
|
+
const authHeader = req.headers.authorization;
|
|
23
|
+
const key = authHeader
|
|
24
|
+
? `auth:${simpleHash(authHeader)}`
|
|
25
|
+
: `ip:${req.ip || req.socket.remoteAddress || "unknown"}`;
|
|
26
|
+
const now = Date.now();
|
|
27
|
+
let record = hits.get(key);
|
|
28
|
+
if (!record || record.resetAt <= now) {
|
|
29
|
+
record = { count: 0, resetAt: now + windowMs };
|
|
30
|
+
hits.set(key, record);
|
|
31
|
+
}
|
|
32
|
+
record.count++;
|
|
33
|
+
// Set standard rate limit headers
|
|
34
|
+
const remaining = Math.max(0, maxRequests - record.count);
|
|
35
|
+
res.setHeader("X-RateLimit-Limit", maxRequests);
|
|
36
|
+
res.setHeader("X-RateLimit-Remaining", remaining);
|
|
37
|
+
res.setHeader("X-RateLimit-Reset", Math.ceil(record.resetAt / 1000));
|
|
38
|
+
if (record.count > maxRequests) {
|
|
39
|
+
const retryAfter = Math.ceil((record.resetAt - now) / 1000);
|
|
40
|
+
res.setHeader("Retry-After", retryAfter);
|
|
41
|
+
console.error(`[rate-limit] blocked ${key} (${record.count}/${maxRequests} in window)`);
|
|
42
|
+
res.status(429).json({
|
|
43
|
+
error: "rate_limit_exceeded",
|
|
44
|
+
error_description: `Too many requests. Retry after ${retryAfter} seconds.`,
|
|
45
|
+
});
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
next();
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/** Fast non-crypto hash for rate limit keying — not for security */
|
|
52
|
+
function simpleHash(str) {
|
|
53
|
+
let hash = 0;
|
|
54
|
+
for (let i = 0; i < str.length; i++) {
|
|
55
|
+
hash = ((hash << 5) - hash + str.charCodeAt(i)) | 0;
|
|
56
|
+
}
|
|
57
|
+
return hash.toString(36);
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=rate-limiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/middleware/rate-limiter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool invocation audit logger.
|
|
3
|
+
* CoSAI MCP-T12: Log every tool call with tool name, parameters, user ID, timestamp.
|
|
4
|
+
*
|
|
5
|
+
* Logs are written to stderr (structured JSON) for collection by CloudWatch/Datadog/etc.
|
|
6
|
+
*/
|
|
7
|
+
export declare function logToolInvocation(toolName: string, params: Record<string, unknown>, clientId: string, result: {
|
|
8
|
+
success: boolean;
|
|
9
|
+
durationMs: number;
|
|
10
|
+
}): void;
|
|
11
|
+
//# sourceMappingURL=tool-logging.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-logging.d.ts","sourceRoot":"","sources":["../../src/middleware/tool-logging.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC/C,IAAI,CAYN"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool invocation audit logger.
|
|
3
|
+
* CoSAI MCP-T12: Log every tool call with tool name, parameters, user ID, timestamp.
|
|
4
|
+
*
|
|
5
|
+
* Logs are written to stderr (structured JSON) for collection by CloudWatch/Datadog/etc.
|
|
6
|
+
*/
|
|
7
|
+
export function logToolInvocation(toolName, params, clientId, result) {
|
|
8
|
+
const entry = {
|
|
9
|
+
type: "tool_invocation",
|
|
10
|
+
timestamp: new Date().toISOString(),
|
|
11
|
+
tool: toolName,
|
|
12
|
+
clientId,
|
|
13
|
+
params: sanitizeParams(params),
|
|
14
|
+
success: result.success,
|
|
15
|
+
durationMs: result.durationMs,
|
|
16
|
+
};
|
|
17
|
+
console.error(JSON.stringify(entry));
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Redact sensitive parameter values from logs.
|
|
21
|
+
* Keep keys and value types visible for debugging, but mask actual content
|
|
22
|
+
* for fields that might contain user data.
|
|
23
|
+
*/
|
|
24
|
+
function sanitizeParams(params) {
|
|
25
|
+
const sanitized = {};
|
|
26
|
+
for (const [key, value] of Object.entries(params)) {
|
|
27
|
+
if (key === "content" || key === "message") {
|
|
28
|
+
// Log length instead of content to avoid PII in logs
|
|
29
|
+
sanitized[key] = typeof value === "string" ? `[${value.length} chars]` : typeof value;
|
|
30
|
+
}
|
|
31
|
+
else if (key === "file_ids") {
|
|
32
|
+
sanitized[key] = Array.isArray(value) ? `[${value.length} ids]` : typeof value;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
sanitized[key] = value;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return sanitized;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=tool-logging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-logging.js","sourceRoot":"","sources":["../../src/middleware/tool-logging.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAAgB,EAChB,MAA+B,EAC/B,QAAgB,EAChB,MAAgD;IAEhD,MAAM,KAAK,GAAG;QACZ,IAAI,EAAE,iBAAiB;QACvB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,IAAI,EAAE,QAAQ;QACd,QAAQ;QACR,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC;QAC9B,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,UAAU,EAAE,MAAM,CAAC,UAAU;KAC9B,CAAC;IAEF,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;AACvC,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,MAA+B;IACrD,MAAM,SAAS,GAA4B,EAAE,CAAC;IAC9C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YAC3C,qDAAqD;YACrD,SAAS,CAAC,GAAG,CAAC,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,SAAS,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC;QACxF,CAAC;aAAM,IAAI,GAAG,KAAK,UAAU,EAAE,CAAC;YAC9B,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC;QACjF,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACzB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { ElnoraApiClient } from "./services/elnora-api-client.js";
|
|
3
3
|
import { ElnoraConfig } from "./types.js";
|
|
4
|
-
export
|
|
4
|
+
export interface RequestContext {
|
|
5
|
+
client: ElnoraApiClient;
|
|
6
|
+
clientId: string;
|
|
7
|
+
scopes: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare function createElnoraServer(config: ElnoraConfig, getContext: () => RequestContext): McpServer;
|
|
5
10
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAS1C,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,eAAe,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,MAAM,cAAc,GAC/B,SAAS,CAcX"}
|
package/dist/server.js
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
2
3
|
import { registerTaskTools } from "./tools/tasks.js";
|
|
3
4
|
import { registerMessageTools } from "./tools/messages.js";
|
|
4
5
|
import { registerFileTools } from "./tools/files.js";
|
|
5
6
|
import { registerProtocolTools } from "./tools/protocols.js";
|
|
6
|
-
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
const { version } = require("../package.json");
|
|
9
|
+
export function createElnoraServer(config, getContext) {
|
|
7
10
|
const server = new McpServer({
|
|
8
11
|
name: "elnora-mcp-server",
|
|
9
|
-
version
|
|
12
|
+
version,
|
|
10
13
|
});
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
const getClient = () => getContext().client;
|
|
15
|
+
registerTaskTools(server, getClient, getContext);
|
|
16
|
+
registerMessageTools(server, getClient, getContext);
|
|
17
|
+
registerFileTools(server, getClient, getContext);
|
|
18
|
+
registerProtocolTools(server, getClient, getContext);
|
|
15
19
|
return server;
|
|
16
20
|
}
|
|
17
21
|
//# sourceMappingURL=server.js.map
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAwB,CAAC;AAQtE,MAAM,UAAU,kBAAkB,CAChC,MAAoB,EACpB,UAAgC;IAEhC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,mBAAmB;QACzB,OAAO;KACR,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,MAAM,CAAC;IAE5C,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IACjD,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IACpD,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IACjD,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IAErD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { ElnoraConfig, ElnoraTask, ElnoraMessage, ElnoraFile, TokenValidationResult } from "../types.js";
|
|
2
2
|
export declare class ElnoraApiClient {
|
|
3
|
-
private bearerToken;
|
|
4
3
|
private client;
|
|
5
|
-
private tokenValidationUrl;
|
|
6
4
|
constructor(config: ElnoraConfig, bearerToken: string);
|
|
7
5
|
static validateToken(tokenValidationUrl: string, token: string): Promise<TokenValidationResult>;
|
|
8
6
|
createTask(title?: string): Promise<ElnoraTask>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"elnora-api-client.d.ts","sourceRoot":"","sources":["../../src/services/elnora-api-client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGzG,qBAAa,eAAe;
|
|
1
|
+
{"version":3,"file":"elnora-api-client.d.ts","sourceRoot":"","sources":["../../src/services/elnora-api-client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGzG,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAgB;gBAElB,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM;WAcxC,aAAa,CAAC,kBAAkB,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAW/F,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAO/C,SAAS,CACb,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,SAAK,EACV,MAAM,SAAI,GACT,OAAO,CAAC;QAAE,KAAK,EAAE,UAAU,EAAE,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAOjD,eAAe,CACnB,MAAM,EAAE,MAAM,EACd,KAAK,SAAK,EACV,MAAM,SAAI,GACT,OAAO,CAAC;QAAE,KAAK,EAAE,aAAa,EAAE,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IASpD,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC;IAWxF,SAAS,CACb,SAAS,CAAC,EAAE,MAAM,EAClB,KAAK,SAAK,EACV,MAAM,SAAI,GACT,OAAO,CAAC;QAAE,KAAK,EAAE,UAAU,EAAE,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAOjD,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAK5F,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;CAQxF"}
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
2
|
import { REQUEST_TIMEOUT_MS, LONG_REQUEST_TIMEOUT_MS } from "../constants.js";
|
|
3
3
|
export class ElnoraApiClient {
|
|
4
|
-
bearerToken;
|
|
5
4
|
client;
|
|
6
|
-
tokenValidationUrl;
|
|
7
5
|
constructor(config, bearerToken) {
|
|
8
|
-
this.bearerToken = bearerToken;
|
|
9
6
|
this.client = axios.create({
|
|
10
7
|
baseURL: config.apiUrl,
|
|
11
8
|
timeout: REQUEST_TIMEOUT_MS,
|
|
@@ -15,7 +12,6 @@ export class ElnoraApiClient {
|
|
|
15
12
|
Authorization: `Bearer ${bearerToken}`,
|
|
16
13
|
},
|
|
17
14
|
});
|
|
18
|
-
this.tokenValidationUrl = config.tokenValidationUrl;
|
|
19
15
|
}
|
|
20
16
|
// --- Token Validation ---
|
|
21
17
|
static async validateToken(tokenValidationUrl, token) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"elnora-api-client.js","sourceRoot":"","sources":["../../src/services/elnora-api-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAwB,MAAM,OAAO,CAAC;AAE7C,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE9E,MAAM,OAAO,eAAe;
|
|
1
|
+
{"version":3,"file":"elnora-api-client.js","sourceRoot":"","sources":["../../src/services/elnora-api-client.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/files.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { ElnoraApiClient } from "../services/elnora-api-client.js";
|
|
3
|
-
|
|
3
|
+
import { RequestContext } from "../server.js";
|
|
4
|
+
export declare function registerFileTools(server: McpServer, getClient: () => ElnoraApiClient, getContext: () => RequestContext): void;
|
|
4
5
|
//# sourceMappingURL=files.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/tools/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/tools/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAK9C,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,eAAe,EAChC,UAAU,EAAE,MAAM,cAAc,GAC/B,IAAI,CAwEN"}
|
package/dist/tools/files.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { handleApiError } from "../services/error-handler.js";
|
|
3
|
+
import { withGuard } from "./with-guard.js";
|
|
3
4
|
import { CHARACTER_LIMIT } from "../constants.js";
|
|
4
|
-
export function registerFileTools(server, getClient) {
|
|
5
|
+
export function registerFileTools(server, getClient, getContext) {
|
|
5
6
|
server.registerTool("elnora_list_files", {
|
|
6
7
|
title: "List Files",
|
|
7
8
|
description: "List files in your Elnora workspace. Returns file metadata including name, type, and visibility.",
|
|
@@ -11,7 +12,7 @@ export function registerFileTools(server, getClient) {
|
|
|
11
12
|
offset: z.number().int().min(0).default(0).describe("Pagination offset"),
|
|
12
13
|
},
|
|
13
14
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
14
|
-
}, async ({ project_id, limit, offset }) => {
|
|
15
|
+
}, withGuard("elnora_list_files", getContext, async ({ project_id, limit, offset }) => {
|
|
15
16
|
try {
|
|
16
17
|
const result = await getClient().listFiles(project_id, limit, offset);
|
|
17
18
|
return {
|
|
@@ -21,7 +22,7 @@ export function registerFileTools(server, getClient) {
|
|
|
21
22
|
catch (error) {
|
|
22
23
|
return { content: [{ type: "text", text: handleApiError(error) }], isError: true };
|
|
23
24
|
}
|
|
24
|
-
});
|
|
25
|
+
}));
|
|
25
26
|
server.registerTool("elnora_get_file_content", {
|
|
26
27
|
title: "Get File Content",
|
|
27
28
|
description: "Retrieve the content of a specific file by its ID. Returns the file content as text along with metadata.",
|
|
@@ -29,7 +30,7 @@ export function registerFileTools(server, getClient) {
|
|
|
29
30
|
file_id: z.string().uuid().describe("File UUID"),
|
|
30
31
|
},
|
|
31
32
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
32
|
-
}, async ({ file_id }) => {
|
|
33
|
+
}, withGuard("elnora_get_file_content", getContext, async ({ file_id }) => {
|
|
33
34
|
try {
|
|
34
35
|
const result = await getClient().getFileContent(file_id);
|
|
35
36
|
return {
|
|
@@ -39,7 +40,7 @@ export function registerFileTools(server, getClient) {
|
|
|
39
40
|
catch (error) {
|
|
40
41
|
return { content: [{ type: "text", text: handleApiError(error) }], isError: true };
|
|
41
42
|
}
|
|
42
|
-
});
|
|
43
|
+
}));
|
|
43
44
|
server.registerTool("elnora_upload_file", {
|
|
44
45
|
title: "Upload File",
|
|
45
46
|
description: "Upload a text file to Elnora. Files are stored in the user's workspace and can be attached to task messages.",
|
|
@@ -49,7 +50,7 @@ export function registerFileTools(server, getClient) {
|
|
|
49
50
|
file_type: z.string().optional().describe("MIME type (default: text/markdown)"),
|
|
50
51
|
},
|
|
51
52
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
|
52
|
-
}, async ({ name, content, file_type }) => {
|
|
53
|
+
}, withGuard("elnora_upload_file", getContext, async ({ name, content, file_type }) => {
|
|
53
54
|
try {
|
|
54
55
|
const result = await getClient().uploadFile(name, content, file_type);
|
|
55
56
|
return {
|
|
@@ -59,6 +60,6 @@ export function registerFileTools(server, getClient) {
|
|
|
59
60
|
catch (error) {
|
|
60
61
|
return { content: [{ type: "text", text: handleApiError(error) }], isError: true };
|
|
61
62
|
}
|
|
62
|
-
});
|
|
63
|
+
}));
|
|
63
64
|
}
|
|
64
65
|
//# sourceMappingURL=files.js.map
|
package/dist/tools/files.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/tools/files.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/tools/files.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/messages.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { ElnoraApiClient } from "../services/elnora-api-client.js";
|
|
3
|
-
|
|
3
|
+
import { RequestContext } from "../server.js";
|
|
4
|
+
export declare function registerMessageTools(server: McpServer, getClient: () => ElnoraApiClient, getContext: () => RequestContext): void;
|
|
4
5
|
//# sourceMappingURL=messages.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/tools/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/tools/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAI9C,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,eAAe,EAChC,UAAU,EAAE,MAAM,cAAc,GAC/B,IAAI,CA8BN"}
|
package/dist/tools/messages.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { handleApiError } from "../services/error-handler.js";
|
|
3
|
-
|
|
3
|
+
import { withGuard } from "./with-guard.js";
|
|
4
|
+
export function registerMessageTools(server, getClient, getContext) {
|
|
4
5
|
server.registerTool("elnora_send_message", {
|
|
5
6
|
title: "Send Message",
|
|
6
7
|
description: "Send a message to an Elnora task and receive the AI response. The message is processed by Elnora's AI system, which handles protocol generation, research, and data analysis. This operation may take 30-120 seconds for complex requests.",
|
|
7
8
|
inputSchema: {
|
|
8
9
|
task_id: z.string().uuid().describe("Task UUID"),
|
|
9
|
-
message: z.string().min(1).max(
|
|
10
|
+
message: z.string().min(1).max(50_000).describe("Message content (markdown supported)"),
|
|
10
11
|
file_ids: z.array(z.string().uuid()).optional().describe("File IDs to attach"),
|
|
11
12
|
},
|
|
12
13
|
annotations: {
|
|
@@ -15,7 +16,7 @@ export function registerMessageTools(server, getClient) {
|
|
|
15
16
|
idempotentHint: false,
|
|
16
17
|
openWorldHint: true,
|
|
17
18
|
},
|
|
18
|
-
}, async ({ task_id, message, file_ids }) => {
|
|
19
|
+
}, withGuard("elnora_send_message", getContext, async ({ task_id, message, file_ids }) => {
|
|
19
20
|
try {
|
|
20
21
|
const response = await getClient().sendMessage(task_id, message, file_ids);
|
|
21
22
|
return {
|
|
@@ -25,6 +26,6 @@ export function registerMessageTools(server, getClient) {
|
|
|
25
26
|
catch (error) {
|
|
26
27
|
return { content: [{ type: "text", text: handleApiError(error) }], isError: true };
|
|
27
28
|
}
|
|
28
|
-
});
|
|
29
|
+
}));
|
|
29
30
|
}
|
|
30
31
|
//# sourceMappingURL=messages.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/tools/messages.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/tools/messages.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,UAAU,oBAAoB,CAClC,MAAiB,EACjB,SAAgC,EAChC,UAAgC;IAEhC,MAAM,CAAC,YAAY,CACjB,qBAAqB,EACrB;QACE,KAAK,EAAE,cAAc;QACrB,WAAW,EACT,4OAA4O;QAC9O,WAAW,EAAE;YACX,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;YAChD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,sCAAsC,CAAC;YACvF,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oBAAoB,CAAC;SAC/E;QACD,WAAW,EAAE;YACX,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,KAAK;YACrB,aAAa,EAAE,IAAI;SACpB;KACF,EACD,SAAS,CAAC,qBAAqB,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE;QACpF,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,SAAS,EAAE,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;YAC3E,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aAC9E,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC9F,CAAC;IACH,CAAC,CAAC,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { ElnoraApiClient } from "../services/elnora-api-client.js";
|
|
3
|
-
|
|
3
|
+
import { RequestContext } from "../server.js";
|
|
4
|
+
export declare function registerProtocolTools(server: McpServer, getClient: () => ElnoraApiClient, getContext: () => RequestContext): void;
|
|
4
5
|
//# sourceMappingURL=protocols.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocols.d.ts","sourceRoot":"","sources":["../../src/tools/protocols.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"protocols.d.ts","sourceRoot":"","sources":["../../src/tools/protocols.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAI9C,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,eAAe,EAChC,UAAU,EAAE,MAAM,cAAc,GAC/B,IAAI,CAgDN"}
|
package/dist/tools/protocols.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { handleApiError } from "../services/error-handler.js";
|
|
3
|
-
|
|
3
|
+
import { withGuard } from "./with-guard.js";
|
|
4
|
+
export function registerProtocolTools(server, getClient, getContext) {
|
|
4
5
|
server.registerTool("elnora_generate_protocol", {
|
|
5
6
|
title: "Generate Protocol",
|
|
6
7
|
description: `Generate a bioprotocol using Elnora's AI agents. This is a convenience tool that creates a task, sends the description as a message, and returns the generated protocol content. This is the primary tool for hackathon partners. The operation typically takes 30-120 seconds.
|
|
@@ -19,7 +20,7 @@ Examples:
|
|
|
19
20
|
idempotentHint: false,
|
|
20
21
|
openWorldHint: true,
|
|
21
22
|
},
|
|
22
|
-
}, async ({ description, title }) => {
|
|
23
|
+
}, withGuard("elnora_generate_protocol", getContext, async ({ description, title }) => {
|
|
23
24
|
try {
|
|
24
25
|
const client = getClient();
|
|
25
26
|
// 1. Create a task
|
|
@@ -40,6 +41,6 @@ Examples:
|
|
|
40
41
|
catch (error) {
|
|
41
42
|
return { content: [{ type: "text", text: handleApiError(error) }], isError: true };
|
|
42
43
|
}
|
|
43
|
-
});
|
|
44
|
+
}));
|
|
44
45
|
}
|
|
45
46
|
//# sourceMappingURL=protocols.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocols.js","sourceRoot":"","sources":["../../src/tools/protocols.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"protocols.js","sourceRoot":"","sources":["../../src/tools/protocols.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,UAAU,qBAAqB,CACnC,MAAiB,EACjB,SAAgC,EAChC,UAAgC;IAEhC,MAAM,CAAC,YAAY,CACjB,0BAA0B,EAC1B;QACE,KAAK,EAAE,mBAAmB;QAC1B,WAAW,EAAE;;;;;oEAKiD;QAC9D,WAAW,EAAE;YACX,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC;YAC1E,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;SAC/F;QACD,WAAW,EAAE;YACX,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,KAAK;YACrB,aAAa,EAAE,IAAI;SACpB;KACF,EACD,SAAS,CAAC,0BAA0B,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,EAAE;QACjF,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAE3B,mBAAmB;YACnB,MAAM,SAAS,GAAG,KAAK,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YACrD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;YAEhD,uCAAuC;YACvC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;YAEhE,uBAAuB;YACvB,MAAM,MAAM,GAAG;gBACb,OAAO,EAAE,IAAI,CAAC,EAAE;gBAChB,gBAAgB,EAAE,QAAQ,CAAC,OAAO;gBAClC,UAAU,EAAE,QAAQ,CAAC,EAAE;aACxB,CAAC;YAEF,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aAC5E,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC9F,CAAC;IACH,CAAC,CAAC,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-tool scope enforcement.
|
|
3
|
+
* CoSAI MCP-T2: Least privilege — each tool declares required scopes.
|
|
4
|
+
*
|
|
5
|
+
* Scope mapping:
|
|
6
|
+
* - elnora_list_tasks, elnora_get_task_messages → tasks:read
|
|
7
|
+
* - elnora_create_task → tasks:write
|
|
8
|
+
* - elnora_send_message → messages:write
|
|
9
|
+
* - elnora_list_files, elnora_get_file_content → files:read
|
|
10
|
+
* - elnora_upload_file → files:write
|
|
11
|
+
* - elnora_generate_protocol → tasks:write, messages:write
|
|
12
|
+
*/
|
|
13
|
+
export declare const TOOL_SCOPES: Record<string, string[]>;
|
|
14
|
+
/**
|
|
15
|
+
* Check if the given scopes satisfy the required scopes for a tool.
|
|
16
|
+
* Returns the list of missing scopes, or empty array if all present.
|
|
17
|
+
*/
|
|
18
|
+
export declare function checkToolScopes(toolName: string, grantedScopes: string[]): string[];
|
|
19
|
+
//# sourceMappingURL=scope-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope-guard.d.ts","sourceRoot":"","sources":["../../src/tools/scope-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAShD,CAAC;AAEF;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAInF"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-tool scope enforcement.
|
|
3
|
+
* CoSAI MCP-T2: Least privilege — each tool declares required scopes.
|
|
4
|
+
*
|
|
5
|
+
* Scope mapping:
|
|
6
|
+
* - elnora_list_tasks, elnora_get_task_messages → tasks:read
|
|
7
|
+
* - elnora_create_task → tasks:write
|
|
8
|
+
* - elnora_send_message → messages:write
|
|
9
|
+
* - elnora_list_files, elnora_get_file_content → files:read
|
|
10
|
+
* - elnora_upload_file → files:write
|
|
11
|
+
* - elnora_generate_protocol → tasks:write, messages:write
|
|
12
|
+
*/
|
|
13
|
+
export const TOOL_SCOPES = {
|
|
14
|
+
elnora_list_tasks: ["tasks:read"],
|
|
15
|
+
elnora_get_task_messages: ["tasks:read"],
|
|
16
|
+
elnora_create_task: ["tasks:write"],
|
|
17
|
+
elnora_send_message: ["messages:write"],
|
|
18
|
+
elnora_list_files: ["files:read"],
|
|
19
|
+
elnora_get_file_content: ["files:read"],
|
|
20
|
+
elnora_upload_file: ["files:write"],
|
|
21
|
+
elnora_generate_protocol: ["tasks:write", "messages:write"],
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Check if the given scopes satisfy the required scopes for a tool.
|
|
25
|
+
* Returns the list of missing scopes, or empty array if all present.
|
|
26
|
+
*/
|
|
27
|
+
export function checkToolScopes(toolName, grantedScopes) {
|
|
28
|
+
const required = TOOL_SCOPES[toolName];
|
|
29
|
+
if (!required)
|
|
30
|
+
return []; // Unknown tool — no scope check
|
|
31
|
+
return required.filter((s) => !grantedScopes.includes(s));
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=scope-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope-guard.js","sourceRoot":"","sources":["../../src/tools/scope-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,WAAW,GAA6B;IACnD,iBAAiB,EAAE,CAAC,YAAY,CAAC;IACjC,wBAAwB,EAAE,CAAC,YAAY,CAAC;IACxC,kBAAkB,EAAE,CAAC,aAAa,CAAC;IACnC,mBAAmB,EAAE,CAAC,gBAAgB,CAAC;IACvC,iBAAiB,EAAE,CAAC,YAAY,CAAC;IACjC,uBAAuB,EAAE,CAAC,YAAY,CAAC;IACvC,kBAAkB,EAAE,CAAC,aAAa,CAAC;IACnC,wBAAwB,EAAE,CAAC,aAAa,EAAE,gBAAgB,CAAC;CAC5D,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,aAAuB;IACvE,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC,CAAC,gCAAgC;IAC1D,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5D,CAAC"}
|
package/dist/tools/tasks.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { ElnoraApiClient } from "../services/elnora-api-client.js";
|
|
3
|
-
|
|
3
|
+
import { RequestContext } from "../server.js";
|
|
4
|
+
export declare function registerTaskTools(server: McpServer, getClient: () => ElnoraApiClient, getContext: () => RequestContext): void;
|
|
4
5
|
//# sourceMappingURL=tasks.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../../src/tools/tasks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../../src/tools/tasks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAI9C,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,eAAe,EAChC,UAAU,EAAE,MAAM,cAAc,GAC/B,IAAI,CA8EN"}
|