@drumbeats/mcp 0.1.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 +130 -0
- package/dist/api/client.d.ts +47 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +57 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/errors.d.ts +14 -0
- package/dist/api/errors.d.ts.map +1 -0
- package/dist/api/errors.js +59 -0
- package/dist/api/errors.js.map +1 -0
- package/dist/api/schemas.d.ts +14 -0
- package/dist/api/schemas.d.ts.map +1 -0
- package/dist/api/schemas.js +13 -0
- package/dist/api/schemas.js.map +1 -0
- package/dist/auth/resource-metadata.d.ts +22 -0
- package/dist/auth/resource-metadata.d.ts.map +1 -0
- package/dist/auth/resource-metadata.js +18 -0
- package/dist/auth/resource-metadata.js.map +1 -0
- package/dist/auth/scope-map.d.ts +20 -0
- package/dist/auth/scope-map.d.ts.map +1 -0
- package/dist/auth/scope-map.js +32 -0
- package/dist/auth/scope-map.js.map +1 -0
- package/dist/auth/verify-token.d.ts +29 -0
- package/dist/auth/verify-token.d.ts.map +1 -0
- package/dist/auth/verify-token.js +23 -0
- package/dist/auth/verify-token.js.map +1 -0
- package/dist/config.d.ts +16 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +32 -0
- package/dist/config.js.map +1 -0
- package/dist/server-http.d.ts +2 -0
- package/dist/server-http.d.ts.map +1 -0
- package/dist/server-http.js +83 -0
- package/dist/server-http.js.map +1 -0
- package/dist/stdio.d.ts +3 -0
- package/dist/stdio.d.ts.map +1 -0
- package/dist/stdio.js +35 -0
- package/dist/stdio.js.map +1 -0
- package/dist/tools/context/list-projects.d.ts +21 -0
- package/dist/tools/context/list-projects.d.ts.map +1 -0
- package/dist/tools/context/list-projects.js +73 -0
- package/dist/tools/context/list-projects.js.map +1 -0
- package/dist/tools/diagnostics/check-dns.d.ts +13 -0
- package/dist/tools/diagnostics/check-dns.d.ts.map +1 -0
- package/dist/tools/diagnostics/check-dns.js +25 -0
- package/dist/tools/diagnostics/check-dns.js.map +1 -0
- package/dist/tools/diagnostics/check-http.d.ts +20 -0
- package/dist/tools/diagnostics/check-http.d.ts.map +1 -0
- package/dist/tools/diagnostics/check-http.js +30 -0
- package/dist/tools/diagnostics/check-http.js.map +1 -0
- package/dist/tools/diagnostics/check-ssl.d.ts +15 -0
- package/dist/tools/diagnostics/check-ssl.d.ts.map +1 -0
- package/dist/tools/diagnostics/check-ssl.js +26 -0
- package/dist/tools/diagnostics/check-ssl.js.map +1 -0
- package/dist/tools/incidents/list-incidents.d.ts +25 -0
- package/dist/tools/incidents/list-incidents.d.ts.map +1 -0
- package/dist/tools/incidents/list-incidents.js +39 -0
- package/dist/tools/incidents/list-incidents.js.map +1 -0
- package/dist/tools/incidents/manage-incident.d.ts +19 -0
- package/dist/tools/incidents/manage-incident.d.ts.map +1 -0
- package/dist/tools/incidents/manage-incident.js +30 -0
- package/dist/tools/incidents/manage-incident.js.map +1 -0
- package/dist/tools/incidents/shared.d.ts +25 -0
- package/dist/tools/incidents/shared.d.ts.map +1 -0
- package/dist/tools/incidents/shared.js +14 -0
- package/dist/tools/incidents/shared.js.map +1 -0
- package/dist/tools/index.d.ts +5 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +45 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/monitors/create-monitor.d.ts +46 -0
- package/dist/tools/monitors/create-monitor.d.ts.map +1 -0
- package/dist/tools/monitors/create-monitor.js +98 -0
- package/dist/tools/monitors/create-monitor.js.map +1 -0
- package/dist/tools/monitors/get-monitor-history.d.ts +29 -0
- package/dist/tools/monitors/get-monitor-history.d.ts.map +1 -0
- package/dist/tools/monitors/get-monitor-history.js +68 -0
- package/dist/tools/monitors/get-monitor-history.js.map +1 -0
- package/dist/tools/monitors/get-monitor.d.ts +13 -0
- package/dist/tools/monitors/get-monitor.d.ts.map +1 -0
- package/dist/tools/monitors/get-monitor.js +23 -0
- package/dist/tools/monitors/get-monitor.js.map +1 -0
- package/dist/tools/monitors/list-monitors.d.ts +13 -0
- package/dist/tools/monitors/list-monitors.d.ts.map +1 -0
- package/dist/tools/monitors/list-monitors.js +29 -0
- package/dist/tools/monitors/list-monitors.js.map +1 -0
- package/dist/tools/monitors/pause-resume.d.ts +16 -0
- package/dist/tools/monitors/pause-resume.d.ts.map +1 -0
- package/dist/tools/monitors/pause-resume.js +41 -0
- package/dist/tools/monitors/pause-resume.js.map +1 -0
- package/dist/tools/monitors/shared.d.ts +40 -0
- package/dist/tools/monitors/shared.d.ts.map +1 -0
- package/dist/tools/monitors/shared.js +21 -0
- package/dist/tools/monitors/shared.js.map +1 -0
- package/dist/tools/monitors/update-monitor.d.ts +50 -0
- package/dist/tools/monitors/update-monitor.d.ts.map +1 -0
- package/dist/tools/monitors/update-monitor.js +75 -0
- package/dist/tools/monitors/update-monitor.js.map +1 -0
- package/dist/tools/result.d.ts +8 -0
- package/dist/tools/result.d.ts.map +1 -0
- package/dist/tools/result.js +13 -0
- package/dist/tools/result.js.map +1 -0
- package/dist/tools/types.d.ts +13 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/uptime/get-uptime-summary.d.ts +15 -0
- package/dist/tools/uptime/get-uptime-summary.d.ts.map +1 -0
- package/dist/tools/uptime/get-uptime-summary.js +69 -0
- package/dist/tools/uptime/get-uptime-summary.js.map +1 -0
- package/dist/tools/validation.d.ts +5 -0
- package/dist/tools/validation.d.ts.map +1 -0
- package/dist/tools/validation.js +7 -0
- package/dist/tools/validation.js.map +1 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +7 -0
- package/dist/version.js.map +1 -0
- package/manifest.json +35 -0
- package/package.json +64 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth token scope ↔ tool availability (the Drumbeats API key-scope model), reused
|
|
3
|
+
* verbatim from the stdio account-key model. The hosted transport reads these
|
|
4
|
+
* scopes from the verified OAuth token; stdio reads them from the account key.
|
|
5
|
+
*/
|
|
6
|
+
export const SCOPES = ['read', 'manage_monitors'];
|
|
7
|
+
/**
|
|
8
|
+
* Tools unlocked by each scope. `read` is always granted; `manage_monitors`
|
|
9
|
+
* adds the write/lifecycle tools.
|
|
10
|
+
*
|
|
11
|
+
* Scaffold stub: the tool-name lists are populated in the tool phase. The
|
|
12
|
+
* structure exists from day one so the least-privilege gate is real.
|
|
13
|
+
*/
|
|
14
|
+
export const TOOLS_BY_SCOPE = {
|
|
15
|
+
read: [],
|
|
16
|
+
manage_monitors: [],
|
|
17
|
+
};
|
|
18
|
+
/** Returns the set of tool names available for a set of granted scopes. */
|
|
19
|
+
export function toolsForScopes(scopes) {
|
|
20
|
+
const tools = new Set();
|
|
21
|
+
for (const scope of scopes) {
|
|
22
|
+
for (const tool of TOOLS_BY_SCOPE[scope]) {
|
|
23
|
+
tools.add(tool);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return tools;
|
|
27
|
+
}
|
|
28
|
+
/** Type guard: is an arbitrary string one of the known scopes? */
|
|
29
|
+
export function isScope(value) {
|
|
30
|
+
return SCOPES.includes(value);
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=scope-map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope-map.js","sourceRoot":"","sources":["../../src/auth/scope-map.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAU,CAAA;AAG1D;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,cAAc,GAA+C;IACxE,IAAI,EAAE,EAAE;IACR,eAAe,EAAE,EAAE;CACpB,CAAA;AAED,2EAA2E;AAC3E,MAAM,UAAU,cAAc,CAAC,MAAwB;IACrD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAA;IAC/B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,KAAK,MAAM,IAAI,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;YACzC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACjB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,OAAQ,MAA4B,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;AACtD,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Scope } from './scope-map.js';
|
|
2
|
+
/** A successfully verified OAuth 2.1 bearer token. */
|
|
3
|
+
export interface VerifiedToken {
|
|
4
|
+
readonly subject: string;
|
|
5
|
+
readonly scopes: readonly Scope[];
|
|
6
|
+
readonly audience: string;
|
|
7
|
+
readonly expiresAt: number;
|
|
8
|
+
/** The raw token, forwarded as the Bearer credential to the REST API. */
|
|
9
|
+
readonly raw: string;
|
|
10
|
+
}
|
|
11
|
+
export interface VerifyTokenOptions {
|
|
12
|
+
/** The MCP resource identifier the token's `aud` MUST match (RFC 8707). */
|
|
13
|
+
readonly expectedAudience: string;
|
|
14
|
+
}
|
|
15
|
+
/** Raised when a bearer token is missing, malformed, expired, or mis-audienced. */
|
|
16
|
+
export declare class TokenVerificationError extends Error {
|
|
17
|
+
constructor(message: string);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Validates an inbound OAuth 2.1 bearer token: signature, expiry, audience
|
|
21
|
+
* (RFC 8707) and scope. Hosted transport only.
|
|
22
|
+
*
|
|
23
|
+
* Scaffold stub — intentionally not implemented. The hosted path is gated on
|
|
24
|
+
* the `id`-service OAuth upgrades (audience + scope claims, public-client PKCE,
|
|
25
|
+
* discovery metadata). Until those land this fails closed, so the hosted
|
|
26
|
+
* transport never accepts an unverified token.
|
|
27
|
+
*/
|
|
28
|
+
export declare function verifyBearerToken(token: string, options: VerifyTokenOptions): Promise<VerifiedToken>;
|
|
29
|
+
//# sourceMappingURL=verify-token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-token.d.ts","sourceRoot":"","sources":["../../src/auth/verify-token.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAE3C,sDAAsD;AACtD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAA;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,yEAAyE;IACzE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,2EAA2E;IAC3E,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;CAClC;AAED,mFAAmF;AACnF,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CASpG"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Raised when a bearer token is missing, malformed, expired, or mis-audienced. */
|
|
2
|
+
export class TokenVerificationError extends Error {
|
|
3
|
+
constructor(message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = 'TokenVerificationError';
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Validates an inbound OAuth 2.1 bearer token: signature, expiry, audience
|
|
10
|
+
* (RFC 8707) and scope. Hosted transport only.
|
|
11
|
+
*
|
|
12
|
+
* Scaffold stub — intentionally not implemented. The hosted path is gated on
|
|
13
|
+
* the `id`-service OAuth upgrades (audience + scope claims, public-client PKCE,
|
|
14
|
+
* discovery metadata). Until those land this fails closed, so the hosted
|
|
15
|
+
* transport never accepts an unverified token.
|
|
16
|
+
*/
|
|
17
|
+
export function verifyBearerToken(token, options) {
|
|
18
|
+
if (token.length === 0) {
|
|
19
|
+
return Promise.reject(new TokenVerificationError('missing bearer token'));
|
|
20
|
+
}
|
|
21
|
+
return Promise.reject(new TokenVerificationError(`token verification not implemented in scaffold (expected audience: ${options.expectedAudience})`));
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=verify-token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-token.js","sourceRoot":"","sources":["../../src/auth/verify-token.ts"],"names":[],"mappings":"AAiBA,mFAAmF;AACnF,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAC/C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAA;IACtC,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAa,EAAE,OAA2B;IAC1E,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,sBAAsB,CAAC,sBAAsB,CAAC,CAAC,CAAA;IAC3E,CAAC;IACD,OAAO,OAAO,CAAC,MAAM,CACnB,IAAI,sBAAsB,CACxB,sEAAsE,OAAO,CAAC,gBAAgB,GAAG,CAClG,CACF,CAAA;AACH,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface AppConfig {
|
|
2
|
+
readonly nodeEnv: 'development' | 'production' | 'test';
|
|
3
|
+
readonly logLevel: 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace';
|
|
4
|
+
readonly port: number;
|
|
5
|
+
readonly apiBaseUrl: string;
|
|
6
|
+
readonly requestTimeoutMs: number;
|
|
7
|
+
/** Present only for the stdio transport. */
|
|
8
|
+
readonly apiKey?: string;
|
|
9
|
+
/** Present only for the hosted transport (canonical MCP resource URL). */
|
|
10
|
+
readonly resourceUrl?: string;
|
|
11
|
+
/** Present only for the hosted transport (authorization server base URL). */
|
|
12
|
+
readonly authServer?: string;
|
|
13
|
+
}
|
|
14
|
+
/** Parses and validates process environment into a typed, immutable config. */
|
|
15
|
+
export declare function loadConfig(env?: NodeJS.ProcessEnv): AppConfig;
|
|
16
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,OAAO,EAAE,aAAa,GAAG,YAAY,GAAG,MAAM,CAAA;IACvD,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAA;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;IACjC,4CAA4C;IAC5C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,0EAA0E;IAC1E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,6EAA6E;IAC7E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED,+EAA+E;AAC/E,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,SAAS,CAY1E"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const DEFAULT_API_BASE_URL = 'https://api.drumbeats.io';
|
|
3
|
+
const DEFAULT_PORT = 3000;
|
|
4
|
+
const DEFAULT_TIMEOUT_MS = 15_000;
|
|
5
|
+
const urlString = z.string().refine((value) => URL.canParse(value), { message: 'must be a valid URL' });
|
|
6
|
+
const envSchema = z.object({
|
|
7
|
+
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
|
|
8
|
+
LOG_LEVEL: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).default('info'),
|
|
9
|
+
PORT: z.coerce.number().int().positive().default(DEFAULT_PORT),
|
|
10
|
+
DRUMBEATS_API_BASE_URL: urlString.default(DEFAULT_API_BASE_URL),
|
|
11
|
+
DRUMBEATS_API_TIMEOUT_MS: z.coerce.number().int().positive().default(DEFAULT_TIMEOUT_MS),
|
|
12
|
+
// stdio transport: an account-scoped Drumbeats API key (dk_…).
|
|
13
|
+
DRUMBEATS_API_KEY: z.string().min(1).optional(),
|
|
14
|
+
// hosted transport: OAuth 2.1 resource-server identifiers, see src/auth.
|
|
15
|
+
MCP_RESOURCE_URL: urlString.optional(),
|
|
16
|
+
MCP_AUTH_SERVER: urlString.optional(),
|
|
17
|
+
});
|
|
18
|
+
/** Parses and validates process environment into a typed, immutable config. */
|
|
19
|
+
export function loadConfig(env = process.env) {
|
|
20
|
+
const parsed = envSchema.parse(env);
|
|
21
|
+
return {
|
|
22
|
+
nodeEnv: parsed.NODE_ENV,
|
|
23
|
+
logLevel: parsed.LOG_LEVEL,
|
|
24
|
+
port: parsed.PORT,
|
|
25
|
+
apiBaseUrl: parsed.DRUMBEATS_API_BASE_URL,
|
|
26
|
+
requestTimeoutMs: parsed.DRUMBEATS_API_TIMEOUT_MS,
|
|
27
|
+
apiKey: parsed.DRUMBEATS_API_KEY,
|
|
28
|
+
resourceUrl: parsed.MCP_RESOURCE_URL,
|
|
29
|
+
authServer: parsed.MCP_AUTH_SERVER,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,MAAM,oBAAoB,GAAG,0BAA0B,CAAA;AACvD,MAAM,YAAY,GAAG,IAAI,CAAA;AACzB,MAAM,kBAAkB,GAAG,MAAM,CAAA;AAEjC,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC,CAAA;AAEvG,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IACzB,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;IAC9E,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IACvF,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC;IAC9D,sBAAsB,EAAE,SAAS,CAAC,OAAO,CAAC,oBAAoB,CAAC;IAC/D,wBAAwB,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,kBAAkB,CAAC;IACxF,+DAA+D;IAC/D,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC/C,yEAAyE;IACzE,gBAAgB,EAAE,SAAS,CAAC,QAAQ,EAAE;IACtC,eAAe,EAAE,SAAS,CAAC,QAAQ,EAAE;CACtC,CAAC,CAAA;AAgBF,+EAA+E;AAC/E,MAAM,UAAU,UAAU,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC7D,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACnC,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,QAAQ;QACxB,QAAQ,EAAE,MAAM,CAAC,SAAS;QAC1B,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,UAAU,EAAE,MAAM,CAAC,sBAAsB;QACzC,gBAAgB,EAAE,MAAM,CAAC,wBAAwB;QACjD,MAAM,EAAE,MAAM,CAAC,iBAAiB;QAChC,WAAW,EAAE,MAAM,CAAC,gBAAgB;QACpC,UAAU,EAAE,MAAM,CAAC,eAAe;KACnC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-http.d.ts","sourceRoot":"","sources":["../src/server-http.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
3
|
+
import express, {} from 'express';
|
|
4
|
+
import { DrumbeatsApiClient } from './api/client.js';
|
|
5
|
+
import { buildProtectedResourceMetadata, PROTECTED_RESOURCE_METADATA_PATH } from './auth/resource-metadata.js';
|
|
6
|
+
import { TokenVerificationError, verifyBearerToken } from './auth/verify-token.js';
|
|
7
|
+
import { loadConfig } from './config.js';
|
|
8
|
+
import { registerTools } from './tools/index.js';
|
|
9
|
+
import { SERVER_NAME, SERVER_VERSION } from './version.js';
|
|
10
|
+
const config = loadConfig();
|
|
11
|
+
const app = express();
|
|
12
|
+
app.use(express.json());
|
|
13
|
+
// Liveness probe on its own unprefixed path (for the reverse proxy / orchestrator healthcheck).
|
|
14
|
+
app.get('/healthz', (_req, res) => {
|
|
15
|
+
res.json({ status: 'ok', service: SERVER_NAME, version: SERVER_VERSION });
|
|
16
|
+
});
|
|
17
|
+
// RFC 9728 discovery document, pointing clients at the authorization server.
|
|
18
|
+
app.get(PROTECTED_RESOURCE_METADATA_PATH, (_req, res) => {
|
|
19
|
+
if (config.resourceUrl === undefined || config.authServer === undefined) {
|
|
20
|
+
res.status(501).json({ error: 'hosted OAuth metadata is not configured' });
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
res.json(buildProtectedResourceMetadata({ resourceUrl: config.resourceUrl, authServerUrl: config.authServer }));
|
|
24
|
+
});
|
|
25
|
+
function bearerFrom(req) {
|
|
26
|
+
const header = req.header('authorization');
|
|
27
|
+
if (header === undefined) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
const [scheme, value] = header.split(' ');
|
|
31
|
+
return scheme?.toLowerCase() === 'bearer' ? value : undefined;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The single MCP endpoint. Per request: verify the OAuth bearer, build a
|
|
35
|
+
* per-session authenticated REST client, register the (currently empty) tool
|
|
36
|
+
* layer, then let the Streamable HTTP transport handle the JSON-RPC exchange.
|
|
37
|
+
*/
|
|
38
|
+
async function handleMcpRequest(req, res) {
|
|
39
|
+
const token = bearerFrom(req);
|
|
40
|
+
if (token === undefined) {
|
|
41
|
+
const base = config.resourceUrl ?? '';
|
|
42
|
+
res
|
|
43
|
+
.status(401)
|
|
44
|
+
.set('WWW-Authenticate', `Bearer resource_metadata="${base}${PROTECTED_RESOURCE_METADATA_PATH}"`)
|
|
45
|
+
.json({ error: 'missing bearer token' });
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const verified = await verifyBearerToken(token, { expectedAudience: config.resourceUrl ?? '' });
|
|
50
|
+
const ctx = {
|
|
51
|
+
api: new DrumbeatsApiClient({
|
|
52
|
+
baseUrl: config.apiBaseUrl,
|
|
53
|
+
auth: { kind: 'bearer', token: verified.raw },
|
|
54
|
+
requestTimeoutMs: config.requestTimeoutMs,
|
|
55
|
+
}),
|
|
56
|
+
};
|
|
57
|
+
const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION });
|
|
58
|
+
registerTools(server, ctx);
|
|
59
|
+
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
|
|
60
|
+
res.on('close', () => {
|
|
61
|
+
void transport.close();
|
|
62
|
+
void server.close();
|
|
63
|
+
});
|
|
64
|
+
await server.connect(transport);
|
|
65
|
+
await transport.handleRequest(req, res, req.body);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
if (!res.headersSent) {
|
|
69
|
+
const status = error instanceof TokenVerificationError ? 401 : 500;
|
|
70
|
+
res.status(status).json({ error: status === 401 ? 'unauthorized' : 'internal error' });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
app.post('/mcp', (req, res) => {
|
|
75
|
+
void handleMcpRequest(req, res);
|
|
76
|
+
});
|
|
77
|
+
function main() {
|
|
78
|
+
app.listen(config.port, () => {
|
|
79
|
+
process.stdout.write(`${SERVER_NAME} (http) listening on :${config.port}\n`);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
main();
|
|
83
|
+
//# sourceMappingURL=server-http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-http.js","sourceRoot":"","sources":["../src/server-http.ts"],"names":[],"mappings":"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"}
|
package/dist/stdio.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":""}
|
package/dist/stdio.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { DrumbeatsApiClient } from './api/client.js';
|
|
5
|
+
import { loadConfig } from './config.js';
|
|
6
|
+
import { registerTools } from './tools/index.js';
|
|
7
|
+
import { SERVER_NAME, SERVER_VERSION } from './version.js';
|
|
8
|
+
/**
|
|
9
|
+
* Local fallback entrypoint: stdio transport authenticated with a Drumbeats
|
|
10
|
+
* account API key (dk_…) from DRUMBEATS_API_KEY. Same shared tool layer as the
|
|
11
|
+
* hosted server — the only difference is how the API client is authenticated.
|
|
12
|
+
*/
|
|
13
|
+
async function main() {
|
|
14
|
+
const config = loadConfig();
|
|
15
|
+
if (config.apiKey === undefined) {
|
|
16
|
+
process.stderr.write('DRUMBEATS_API_KEY is required for the stdio transport.\n');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
const ctx = {
|
|
20
|
+
api: new DrumbeatsApiClient({
|
|
21
|
+
baseUrl: config.apiBaseUrl,
|
|
22
|
+
auth: { kind: 'apiKey', apiKey: config.apiKey },
|
|
23
|
+
requestTimeoutMs: config.requestTimeoutMs,
|
|
24
|
+
}),
|
|
25
|
+
};
|
|
26
|
+
const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION });
|
|
27
|
+
registerTools(server, ctx);
|
|
28
|
+
const transport = new StdioServerTransport();
|
|
29
|
+
await server.connect(transport);
|
|
30
|
+
}
|
|
31
|
+
main().catch((error) => {
|
|
32
|
+
process.stderr.write(`fatal: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=stdio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAChF,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAEhD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAE1D;;;;GAIG;AACH,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;IAC3B,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAA;QAChF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,MAAM,GAAG,GAAgB;QACvB,GAAG,EAAE,IAAI,kBAAkB,CAAC;YAC1B,OAAO,EAAE,MAAM,CAAC,UAAU;YAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;YAC/C,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;SAC1C,CAAC;KACH,CAAA;IAED,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAA;IAC5E,aAAa,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAE1B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAA;IAC5C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;AACjC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC1F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import type { ToolContext } from '../types.js';
|
|
5
|
+
export declare const listProjectsInputShape: {
|
|
6
|
+
include: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
7
|
+
channels: "channels";
|
|
8
|
+
groups: "groups";
|
|
9
|
+
}>>>;
|
|
10
|
+
};
|
|
11
|
+
export type ListProjectsArgs = {
|
|
12
|
+
include?: Array<'channels' | 'groups'>;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Core handler, kept separate from registration so it can be unit-tested with a
|
|
16
|
+
* mocked ApiClient and no network.
|
|
17
|
+
*/
|
|
18
|
+
export declare function listProjects(ctx: ToolContext, args: ListProjectsArgs): Promise<CallToolResult>;
|
|
19
|
+
/** Registers the `list_projects` tool against the MCP server. */
|
|
20
|
+
export declare function registerListProjects(server: McpServer, ctx: ToolContext): void;
|
|
21
|
+
//# sourceMappingURL=list-projects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-projects.d.ts","sourceRoot":"","sources":["../../../src/tools/context/list-projects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAA;AACxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAuD9C,eAAO,MAAM,sBAAsB;;;;;CAOlC,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAAE,OAAO,CAAC,EAAE,KAAK,CAAC,UAAU,GAAG,QAAQ,CAAC,CAAA;CAAE,CAAA;AAoBzE;;;GAGG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,cAAc,CAAC,CA0CpG;AAED,iEAAiE;AACjE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAM9E"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { toToolErrorResult } from '../../api/errors.js';
|
|
3
|
+
import { jsonResult } from '../result.js';
|
|
4
|
+
export const listProjectsInputShape = {
|
|
5
|
+
include: z
|
|
6
|
+
.array(z.enum(['channels', 'groups']))
|
|
7
|
+
.optional()
|
|
8
|
+
.describe('Optionally also fetch, per project, its notification channels and/or groups. Their ids are needed to wire alerts when creating a monitor.'),
|
|
9
|
+
};
|
|
10
|
+
const DESCRIPTION = 'List all Drumbeats projects the configured account API key can access. Returns each project id, ' +
|
|
11
|
+
'name, plan, and basic metadata — use it to find the target project id before creating or querying ' +
|
|
12
|
+
'monitors. Pass include=["channels","groups"] to also return each project\'s notification channels ' +
|
|
13
|
+
'and groups, whose ids are needed to wire alerts when creating a monitor.';
|
|
14
|
+
function toProjectSummary(project) {
|
|
15
|
+
return {
|
|
16
|
+
id: project.id,
|
|
17
|
+
name: project.name,
|
|
18
|
+
description: project.description ?? null,
|
|
19
|
+
plan: project.plan ?? null,
|
|
20
|
+
created_at: project.created_at ?? null,
|
|
21
|
+
member_count: project._count?.members ?? null,
|
|
22
|
+
owner_email: project.owner?.email ?? null,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Core handler, kept separate from registration so it can be unit-tested with a
|
|
27
|
+
* mocked ApiClient and no network.
|
|
28
|
+
*/
|
|
29
|
+
export async function listProjects(ctx, args) {
|
|
30
|
+
try {
|
|
31
|
+
const { projects } = await ctx.api.request({ path: '/v1/projects' });
|
|
32
|
+
const include = new Set(args.include ?? []);
|
|
33
|
+
const wantChannels = include.has('channels');
|
|
34
|
+
const wantGroups = include.has('groups');
|
|
35
|
+
const summaries = await Promise.all((projects ?? []).map(async (project) => {
|
|
36
|
+
const summary = toProjectSummary(project);
|
|
37
|
+
if (wantChannels) {
|
|
38
|
+
const channels = await ctx.api.request({
|
|
39
|
+
path: '/v1/notification-channels',
|
|
40
|
+
query: { project_id: project.id },
|
|
41
|
+
});
|
|
42
|
+
summary.notification_channels = (channels ?? []).map((channel) => ({
|
|
43
|
+
id: channel.id,
|
|
44
|
+
name: channel.name ?? null,
|
|
45
|
+
type: channel.channel ?? null,
|
|
46
|
+
enabled: channel.enabled ?? null,
|
|
47
|
+
is_default: channel.is_default ?? null,
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
if (wantGroups) {
|
|
51
|
+
const groups = await ctx.api.request({
|
|
52
|
+
path: '/v1/notification-groups',
|
|
53
|
+
query: { project_id: project.id },
|
|
54
|
+
});
|
|
55
|
+
summary.notification_groups = (groups ?? []).map((group) => ({
|
|
56
|
+
id: group.id,
|
|
57
|
+
name: group.name,
|
|
58
|
+
description: group.description ?? null,
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
return summary;
|
|
62
|
+
}));
|
|
63
|
+
return jsonResult({ projects: summaries });
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
return toToolErrorResult(error);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** Registers the `list_projects` tool against the MCP server. */
|
|
70
|
+
export function registerListProjects(server, ctx) {
|
|
71
|
+
server.registerTool('list_projects', { title: 'List projects', description: DESCRIPTION, inputSchema: listProjectsInputShape }, (args) => listProjects(ctx, args));
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=list-projects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-projects.js","sourceRoot":"","sources":["../../../src/tools/context/list-projects.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import type { ToolContext } from '../types.js';
|
|
5
|
+
export declare const checkDnsInputShape: {
|
|
6
|
+
hostname: z.ZodString;
|
|
7
|
+
};
|
|
8
|
+
export type CheckDnsArgs = {
|
|
9
|
+
hostname: string;
|
|
10
|
+
};
|
|
11
|
+
export declare function checkDns(ctx: ToolContext, args: CheckDnsArgs): Promise<CallToolResult>;
|
|
12
|
+
export declare function registerCheckDns(server: McpServer, ctx: ToolContext): void;
|
|
13
|
+
//# sourceMappingURL=check-dns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-dns.d.ts","sourceRoot":"","sources":["../../../src/tools/diagnostics/check-dns.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAA;AACxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C,eAAO,MAAM,kBAAkB;;CAE9B,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAA;AAM/C,wBAAsB,QAAQ,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC,CAW5F;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAM1E"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { toToolErrorResult } from '../../api/errors.js';
|
|
3
|
+
import { jsonResult } from '../result.js';
|
|
4
|
+
export const checkDnsInputShape = {
|
|
5
|
+
hostname: z.string().min(1).describe('The hostname to resolve, e.g. example.com (a domain, not an IP).'),
|
|
6
|
+
};
|
|
7
|
+
const DESCRIPTION = 'Resolve a hostname and report its DNS records (what the domain points to). ' +
|
|
8
|
+
'Works with no Drumbeats account or API key — useful for "what does this domain resolve to?".';
|
|
9
|
+
export async function checkDns(ctx, args) {
|
|
10
|
+
try {
|
|
11
|
+
const result = await ctx.api.request({
|
|
12
|
+
method: 'POST',
|
|
13
|
+
path: '/v1/tools/check-dns',
|
|
14
|
+
body: { hostname: args.hostname },
|
|
15
|
+
});
|
|
16
|
+
return jsonResult(result);
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
return toToolErrorResult(error);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export function registerCheckDns(server, ctx) {
|
|
23
|
+
server.registerTool('check_dns', { title: 'Check DNS', description: DESCRIPTION, inputSchema: checkDnsInputShape }, (args) => checkDns(ctx, args));
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=check-dns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-dns.js","sourceRoot":"","sources":["../../../src/tools/diagnostics/check-dns.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAGzC,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,kEAAkE,CAAC;CACzG,CAAA;AAID,MAAM,WAAW,GACf,6EAA6E;IAC7E,8FAA8F,CAAA;AAEhG,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,GAAgB,EAAE,IAAkB;IACjE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;YACnC,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,qBAAqB;YAC3B,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE;SAClC,CAAC,CAAA;QACF,OAAO,UAAU,CAAC,MAAM,CAAC,CAAA;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,iBAAiB,CAAC,KAAK,CAAC,CAAA;IACjC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAiB,EAAE,GAAgB;IAClE,MAAM,CAAC,YAAY,CACjB,WAAW,EACX,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,kBAAkB,EAAE,EACjF,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,CAC9B,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import type { ToolContext } from '../types.js';
|
|
5
|
+
export declare const checkHttpInputShape: {
|
|
6
|
+
url: z.ZodString;
|
|
7
|
+
method: z.ZodOptional<z.ZodEnum<{
|
|
8
|
+
GET: "GET";
|
|
9
|
+
HEAD: "HEAD";
|
|
10
|
+
}>>;
|
|
11
|
+
follow_redirects: z.ZodOptional<z.ZodBoolean>;
|
|
12
|
+
};
|
|
13
|
+
export type CheckHttpArgs = {
|
|
14
|
+
url: string;
|
|
15
|
+
method?: 'GET' | 'HEAD';
|
|
16
|
+
follow_redirects?: boolean;
|
|
17
|
+
};
|
|
18
|
+
export declare function checkHttp(ctx: ToolContext, args: CheckHttpArgs): Promise<CallToolResult>;
|
|
19
|
+
export declare function registerCheckHttp(server: McpServer, ctx: ToolContext): void;
|
|
20
|
+
//# sourceMappingURL=check-http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-http.d.ts","sourceRoot":"","sources":["../../../src/tools/diagnostics/check-http.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAA;AACxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C,eAAO,MAAM,mBAAmB;;;;;;;CAO/B,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAMhG,wBAAsB,SAAS,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAW9F;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAM3E"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { toToolErrorResult } from '../../api/errors.js';
|
|
3
|
+
import { jsonResult } from '../result.js';
|
|
4
|
+
export const checkHttpInputShape = {
|
|
5
|
+
url: z
|
|
6
|
+
.string()
|
|
7
|
+
.refine((value) => URL.canParse(value), { message: 'must be a valid URL' })
|
|
8
|
+
.describe('The http(s) URL to check, e.g. https://example.com'),
|
|
9
|
+
method: z.enum(['GET', 'HEAD']).optional().describe('Request method (default HEAD).'),
|
|
10
|
+
follow_redirects: z.boolean().optional().describe('Whether to follow redirects (default true).'),
|
|
11
|
+
};
|
|
12
|
+
const DESCRIPTION = 'Check whether an http(s) URL is reachable and report its status code and response time. ' +
|
|
13
|
+
'Works with no Drumbeats account or API key — handy for a quick "is this site up?" before signing up.';
|
|
14
|
+
export async function checkHttp(ctx, args) {
|
|
15
|
+
try {
|
|
16
|
+
const result = await ctx.api.request({
|
|
17
|
+
method: 'POST',
|
|
18
|
+
path: '/v1/tools/check-http',
|
|
19
|
+
body: { url: args.url, method: args.method, follow_redirects: args.follow_redirects },
|
|
20
|
+
});
|
|
21
|
+
return jsonResult(result);
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
return toToolErrorResult(error);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function registerCheckHttp(server, ctx) {
|
|
28
|
+
server.registerTool('check_http', { title: 'Check HTTP', description: DESCRIPTION, inputSchema: checkHttpInputShape }, (args) => checkHttp(ctx, args));
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=check-http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-http.js","sourceRoot":"","sources":["../../../src/tools/diagnostics/check-http.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAGzC,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,GAAG,EAAE,CAAC;SACH,MAAM,EAAE;SACR,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC;SAC1E,QAAQ,CAAC,oDAAoD,CAAC;IACjE,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;IACrF,gBAAgB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6CAA6C,CAAC;CACjG,CAAA;AAID,MAAM,WAAW,GACf,0FAA0F;IAC1F,sGAAsG,CAAA;AAExG,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAgB,EAAE,IAAmB;IACnE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;YACnC,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,sBAAsB;YAC5B,IAAI,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE;SACtF,CAAC,CAAA;QACF,OAAO,UAAU,CAAC,MAAM,CAAC,CAAA;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,iBAAiB,CAAC,KAAK,CAAC,CAAA;IACjC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAiB,EAAE,GAAgB;IACnE,MAAM,CAAC,YAAY,CACjB,YAAY,EACZ,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,mBAAmB,EAAE,EACnF,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,CAC/B,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import type { ToolContext } from '../types.js';
|
|
5
|
+
export declare const checkSslInputShape: {
|
|
6
|
+
hostname: z.ZodString;
|
|
7
|
+
port: z.ZodOptional<z.ZodNumber>;
|
|
8
|
+
};
|
|
9
|
+
export type CheckSslArgs = {
|
|
10
|
+
hostname: string;
|
|
11
|
+
port?: number;
|
|
12
|
+
};
|
|
13
|
+
export declare function checkSsl(ctx: ToolContext, args: CheckSslArgs): Promise<CallToolResult>;
|
|
14
|
+
export declare function registerCheckSsl(server: McpServer, ctx: ToolContext): void;
|
|
15
|
+
//# sourceMappingURL=check-ssl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-ssl.d.ts","sourceRoot":"","sources":["../../../src/tools/diagnostics/check-ssl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAA;AACxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C,eAAO,MAAM,kBAAkB;;;CAG9B,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAM9D,wBAAsB,QAAQ,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC,CAW5F;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAM1E"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { toToolErrorResult } from '../../api/errors.js';
|
|
3
|
+
import { jsonResult } from '../result.js';
|
|
4
|
+
export const checkSslInputShape = {
|
|
5
|
+
hostname: z.string().min(1).describe('The hostname to inspect, e.g. example.com (no scheme).'),
|
|
6
|
+
port: z.number().int().min(1).max(65535).optional().describe('TLS port (default 443).'),
|
|
7
|
+
};
|
|
8
|
+
const DESCRIPTION = "Inspect a host's TLS/SSL certificate — validity, expiry date, and issuer. " +
|
|
9
|
+
'Works with no Drumbeats account or API key — useful for "is my SSL certificate about to expire?".';
|
|
10
|
+
export async function checkSsl(ctx, args) {
|
|
11
|
+
try {
|
|
12
|
+
const result = await ctx.api.request({
|
|
13
|
+
method: 'POST',
|
|
14
|
+
path: '/v1/tools/check-ssl',
|
|
15
|
+
body: { hostname: args.hostname, port: args.port },
|
|
16
|
+
});
|
|
17
|
+
return jsonResult(result);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
return toToolErrorResult(error);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function registerCheckSsl(server, ctx) {
|
|
24
|
+
server.registerTool('check_ssl', { title: 'Check SSL', description: DESCRIPTION, inputSchema: checkSslInputShape }, (args) => checkSsl(ctx, args));
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=check-ssl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-ssl.js","sourceRoot":"","sources":["../../../src/tools/diagnostics/check-ssl.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAGzC,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,wDAAwD,CAAC;IAC9F,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yBAAyB,CAAC;CACxF,CAAA;AAID,MAAM,WAAW,GACf,4EAA4E;IAC5E,mGAAmG,CAAA;AAErG,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,GAAgB,EAAE,IAAkB;IACjE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;YACnC,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,qBAAqB;YAC3B,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;SACnD,CAAC,CAAA;QACF,OAAO,UAAU,CAAC,MAAM,CAAC,CAAA;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,iBAAiB,CAAC,KAAK,CAAC,CAAA;IACjC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAiB,EAAE,GAAgB;IAClE,MAAM,CAAC,YAAY,CACjB,WAAW,EACX,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,kBAAkB,EAAE,EACjF,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,CAC9B,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import type { ToolContext } from '../types.js';
|
|
5
|
+
export declare const listIncidentsInputShape: {
|
|
6
|
+
project_id: z.ZodString;
|
|
7
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
8
|
+
OPEN: "OPEN";
|
|
9
|
+
ACKNOWLEDGED: "ACKNOWLEDGED";
|
|
10
|
+
RESOLVED: "RESOLVED";
|
|
11
|
+
}>>;
|
|
12
|
+
monitor_id: z.ZodOptional<z.ZodString>;
|
|
13
|
+
page: z.ZodOptional<z.ZodNumber>;
|
|
14
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
15
|
+
};
|
|
16
|
+
export type ListIncidentsArgs = {
|
|
17
|
+
project_id: string;
|
|
18
|
+
status?: 'OPEN' | 'ACKNOWLEDGED' | 'RESOLVED';
|
|
19
|
+
monitor_id?: string;
|
|
20
|
+
page?: number;
|
|
21
|
+
limit?: number;
|
|
22
|
+
};
|
|
23
|
+
export declare function listIncidents(ctx: ToolContext, args: ListIncidentsArgs): Promise<CallToolResult>;
|
|
24
|
+
export declare function registerListIncidents(server: McpServer, ctx: ToolContext): void;
|
|
25
|
+
//# sourceMappingURL=list-incidents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-incidents.d.ts","sourceRoot":"","sources":["../../../src/tools/incidents/list-incidents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAA;AACxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAK9C,eAAO,MAAM,uBAAuB;;;;;;;;;;CAMnC,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,UAAU,CAAA;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAMD,wBAAsB,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC,CAmBtG;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAM/E"}
|