@redpanda-data/mcp-types
v0.9.1
Published
TypeScript ambient declarations for JavaScript managed MCPs on Redpanda AI Gateway
Keywords
Readme
@redpanda-data/mcp-types
TypeScript ambient declarations for authoring JavaScript managed MCPs on Redpanda AI Gateway.
This package is types-only — it ships no runtime code. The globals it declares
(mcp, fetch, secrets, console) are injected by the Redpanda AI Gateway sandbox
at execution time, the same way a standards-compliant JavaScript runtime provides its
built-in globals. The npm package exists solely to give your editor and TypeScript
compiler the correct type information.
See the JavaScript MCP guide for the full authoring walkthrough.
Install
npm install --save-dev @redpanda-data/mcp-typesUsage
Add a triple-slash reference to your handler source — that's all. No imports, no
require(), no bundling of this package:
/// <reference types="@redpanda-data/mcp-types" />
// All globals (mcp, fetch, secrets, console) are now typed.
mcp.tool({
name: 'get_user',
description: 'Look up an Acme user by their ID.',
inputSchema: {
type: 'object',
required: ['id'],
properties: { id: { type: 'string' } },
},
outputSchema: {
type: 'object',
required: ['id', 'email'],
properties: {
id: { type: 'string' },
email: { type: 'string' },
name: { type: 'string' },
},
},
handler: async ({ id }: { id: string }) => {
const resp = await fetch(`https://api.acme.com/users/${id}`, {
headers: { Authorization: `Bearer ${secrets['ACME_API_KEY']}` },
});
if (!resp.ok) throw new Error(`acme get_user: HTTP ${resp.status}`);
return resp.json();
},
});The triple-slash reference can also go in your tsconfig.json:
{
"compilerOptions": {
"types": ["@redpanda-data/mcp-types"]
}
}Globals
The following globals are injected by the runtime and declared here for type checking:
| Global | Type | Description |
|---|---|---|
| mcp | { tool(def) } | Tool registration. Call at module top level. |
| fetch(input, init?) | async function | Standard WHATWG async fetch. Secret markers are substituted in headers and URLs before dispatch. Validated against allowed_hosts. |
| secrets | Record<string, string> | Proxy returning opaque marker strings for each name in allowed_secrets. The runtime substitutes markers to plaintext at fetch time. |
| console | { log, info, warn, error, debug } | Captured by the runtime and routed to aigw's logger. Marker tokens are auto-redacted. |
| Headers | class | WHATWG Headers |
| Response | class | WHATWG Response |
| Request | class | WHATWG Request — construct one and pass it to fetch() as the first argument, or read its body with arrayBuffer(), text(), json(), formData(), etc. |
| URL, URLSearchParams | classes | WHATWG URL parsing and form-encoded serialization. |
| AbortController | class | WHATWG AbortController |
| AbortSignal | class | WHATWG AbortSignal (incl. static abort(), timeout()) |
| DOMException | class | WHATWG DOMException — thrown by crypto.subtle, atob / btoa, and a few other APIs. Has name, message, and (legacy) numeric code. |
| atob(s), btoa(s) | functions | WHATWG base64 encode/decode (Latin-1 strings). |
| TextEncoder, TextDecoder | classes | WHATWG Encoding subset — UTF-8, UTF-16LE, UTF-16BE only. |
| crypto | { randomUUID, getRandomValues, subtle } | WebCrypto — UUID v4, cryptographically random bytes, and a broad SubtleCrypto surface (RSA-OAEP/PSS/PKCS1-v1_5, ECDSA, ECDH + X25519, Ed25519, HKDF, PBKDF2, AES-GCM/CBC/CTR/KW, HMAC, SHA-2). See the crypto note below. |
| CryptoKey, SubtleCrypto | classes | Exposed for instanceof checks; constructed only via crypto.subtle.importKey(...). |
| Blob, File | classes | WHATWG Blob/File for binary data. stream(), arrayBuffer(), bytes(), text(), and slice() are all available. |
| FormData | class | WHATWG FormData — pass to fetch(url, { body: formData }) to send multipart/form-data with a runtime-generated boundary. The constructor takes no arguments (no DOM in this runtime). |
| ReadableStream | class | WHATWG Streams. Constructor (start/pull/cancel), getReader(), pipeTo, pipeThrough, tee, cancel, locked, async iteration, and static ReadableStream.from(iterable). Default readers only — BYOB ({ mode: 'byob' }, type: 'bytes') is not exposed. |
| WritableStream | class | WHATWG Streams. Constructor (start/write/close/abort), getWriter(), close, abort, locked. |
| TransformStream | class | WHATWG Streams. Constructor (start/transform/flush), readable, writable. |
| CountQueuingStrategy, ByteLengthQueuingStrategy | classes | WHATWG Streams §7 named queuing strategies; plain { highWaterMark, size } objects are accepted too. |
Response exposes arrayBuffer(), bytes(), blob(), formData(),
text(), json(), and body — a ReadableStream<Uint8Array> (or
null for an empty body; repeated access returns the same stream).
Body shapes accepted by fetch(url, { body }): string,
URLSearchParams, ArrayBuffer, ArrayBufferView (any Uint8Array
etc.), Blob, FormData, and ReadableStream (chunks must be
byte-shaped or strings). The Response constructor accepts the same
union MINUS ReadableStream (the runtime has no stream branch there).
fetch() also accepts a Request object as its first argument.
crypto.subtle ships a broad WebCrypto surface: digest (SHA-256/384/512),
HMAC, RSA (OAEP / PSS / PKCS1-v1_5), ECDSA, ECDH + X25519 key agreement,
Ed25519 signatures, HKDF and PBKDF2 key derivation, and AES-GCM / CBC /
CTR / KW. Key formats raw, pkcs8, spki, and jwk are supported
(HKDF / PBKDF2 are raw-import-only, with no jwk), and importKey /
exportKey, sign / verify, encrypt / decrypt, deriveBits /
deriveKey, and wrapKey / unwrapKey are all available.
generateKey works for every family except HKDF / PBKDF2 — derive their
keys from imported material instead. Per-operation key-usage rules follow
the WebCrypto spec with a few documented divergences (see the crypto
matrix in the JavaScript MCP guide).
These declarations are themselves the canonical description of the runtime surface — a parity check keeps them in lockstep with what the sandbox ships.
Named type exports
If you want to use the type names directly (e.g., in a helper file), you can import them as types:
import type { ToolDefinition, ToolHandler } from '@redpanda-data/mcp-types';
// These are pure type imports — nothing is emitted at runtime.
function makeToolDef<A, R>(def: ToolDefinition<A, R>): ToolDefinition<A, R> {
return def;
}Testing
Because globals are just globalThis properties at runtime, mock them directly in tests.
No special test helpers from this package are needed:
import { beforeEach, describe, expect, test, vi } from 'vitest';
beforeEach(() => {
// Mock the WHATWG fetch global (Response is available in Node.js 18+ / vitest)
globalThis.fetch = vi.fn();
// Mock secrets
const secretMap: Record<string, string> = { ACME_API_KEY: 'test-key' };
globalThis.secrets = new Proxy({} as Record<string, string>, {
get: (_, k: string) => secretMap[k],
});
});
describe('get_user', () => {
test('makes the right request', async () => {
(globalThis.fetch as ReturnType<typeof vi.fn>).mockResolvedValue(
new Response(JSON.stringify({ id: 'u1', email: '[email protected]' }), { status: 200 }),
);
await import('../src/index.js'); // registers mcp.tool(...) side effects
// then drive the registered tool via a small test harness (see below)
});
});Test harness for invoking registered tools
Because mcp.tool(...) is a side-effectful registration, tests need a small shim to
capture registrations and invoke handlers. The pattern is:
- Before importing your handler module, set
globalThis.mcpto a recording object. - Import the handler module — each
mcp.tool(...)call records the definition. - Use
runTool(name, args)from the harness to invoke a registered handler.
The JavaScript MCP guide includes a ready-to-copy ~30-line harness you can drop into your project.
Starter template
The JavaScript MCP guide walks through a complete working example end to end: tool declarations, vitest tests, a test harness, and an esbuild bundle config.
