temporal-mcp
by stevekinney
README.md
# Temporal MCP
An MCP server that gives AI agents read-only access to your Temporal infrastructure — plus an Agent Skill that provides expert Temporal development guidance.
The server exposes 28 tools across six categories—workflows, schedules, infrastructure, workers, connections, and documentation—along with 5 resource types, 4 prompt templates, a built-in documentation search subsystem, and a policy engine that controls what agents are allowed to see. Temporal operations are read-only (no writes to Temporal state). The `docs.refresh` tool does have local side effects: it performs network `git` syncs and writes cache/index files under `~/.temporal-mcp`.
## Agent Skill
`temporal-mcp` ships a spec-compliant [Agent Skill](https://agentskills.io/specification) at `skill/SKILL.md`. The skill is a curated knowledge package — markdown reference files covering Temporal architecture, determinism rules, workflow patterns, common gotchas, versioning strategies, troubleshooting decision trees, and language-specific guidance for TypeScript, Python, and Go.
The skill and the MCP server solve complementary problems:
- The **skill** teaches agents how to *write* correct Temporal code
- The **MCP server** lets agents *observe* running infrastructure
**Install the skill standalone** (no MCP server required):
```bash
# Claude Code / Claude Desktop (skills directory)
cp -r skill/ ~/.claude/skills/temporal-mcp/
```
**Or use it via the MCP server** — the skill is included in the package. When both are active, tools like `temporal.workflow.describe` return a `guidance` field pointing to the relevant reference file when the workflow is in a notable state (failed, timed out, etc.), and `docs.search` searches both the Temporal docs corpus and the curated references.
## Features
- **28 read-only tools** for inspecting workflows, schedules, task queues, namespaces, workers, and cluster state
- **5 MCP resource types** for direct access to Temporal entities via URI templates
- **4 prompt templates** (`temporal-debug-workflow`, `temporal-triage`, `temporal-docs-answer`, `temporal-safe-mutation`) that combine live cluster data with curated guidance
- **Agent Skill** at `skill/SKILL.md` with 22 curated reference files for TypeScript, Python, and Go development
- **Documentation subsystem** that indexes and searches the Temporal docs corpus plus curated references locally
- **Multi-profile connections** to multiple Temporal clusters (self-hosted and Cloud) from one server
- **Policy engine** with four modes, glob-based tool filtering, and profile/namespace allowlists
- **Audit logging** with structured JSON to `stderr` and automatic sensitive field redaction
- **Zero Temporal write operations** by design—no starts, signals, cancels, terminates, or deletes
## Using Both Together
When the MCP server is connected to a Temporal cluster and the skill is loaded into the agent's context, the two capabilities reinforce each other:
- **`temporal.workflow.describe`** on a timed-out or failed workflow returns a `guidance` field: `"See skill/references/core/gotchas.md for common timeout causes..."`. The agent can then load that reference file to understand the failure and how to fix the code.
- **`temporal.workflow.history.summarize`** detecting workflow task failures (often non-determinism errors) returns guidance pointing to `skill/references/core/determinism.md` and `skill/references/core/versioning.md`.
- **`docs.search`** searches both the Temporal documentation corpus and the curated reference files, with curated results ranked higher (they're more information-dense).
- **`docs.get`** can retrieve curated reference files directly: `docs.get({ sourcePath: "skill/references/core/determinism.md" })`.
- **Prompt templates** (`temporal-debug-workflow`, `temporal-triage`) orchestrate multi-step diagnostic workflows that interleave MCP tool calls with curated knowledge lookups.
## Prerequisites
- [Node.js](https://nodejs.org) 20+ runtime
- A running Temporal cluster (self-hosted) or a Temporal Cloud account
- An MCP-compatible client (Claude Desktop, Claude Code, or any client that speaks `stdio` transport)
## Installation
```bash
npx -y temporal-mcp
```
For local development builds:
```bash
bun install
bun run build
node dist/cli.js
```
The server communicates over `stdio` transport by default. Your MCP client launches it as a subprocess—you don't run it in a separate terminal.
Bun is required for development and build workflows. Runtime execution uses Node.js (`dist/cli.js` or the `temporal-mcp` CLI).
## Configuration
The server looks for configuration in this order, using the first file it finds:
1. The path in the `TEMPORAL_MCP_CONFIG` environment variable
2. `.temporal-mcp.json` in the current working directory
3. `~/.config/temporal-mcp/config.json`
4. Built-in defaults (no profiles configured)
### Self-hosted profile
```json
{
"temporal": {
"defaultProfile": "local",
"profiles": {
"local": {
"kind": "self-hosted",
"address": "localhost:7233",
"namespace": "default"
}
}
}
}
```
### Cloud profile
```json
{
"temporal": {
"defaultProfile": "production",
"profiles": {
"production": {
"kind": "cloud",
"address": "my-namespace.tmprl.cloud:7233",
"namespace": "my-namespace"
}
}
}
}
```
For Cloud connections, set the `TEMPORAL_API_KEY` environment variable with your API key.
### Multiple profiles
```json
{
"temporal": {
"defaultProfile": "local",
"profiles": {
"local": {
"kind": "self-hosted",
"address": "localhost:7233",
"namespace": "default"
},
"production": {
"kind": "cloud",
"address": "my-namespace.tmprl.cloud:7233",
"namespace": "my-namespace"
}
}
}
}
```
Every tool accepts an optional `profile` parameter. When omitted, the server uses `defaultProfile`. When provided, it connects to that specific profile's cluster.
## Connecting to an MCP client
### Claude Desktop
Add this to your `claude_desktop_config.json`:
```json
{
"mcpServers": {
"temporal": {
"command": "npx",
"args": ["-y", "temporal-mcp"]
}
}
}
```
### Claude Code
```bash
claude mcp add temporal -- npx -y temporal-mcp
```
### Other clients
Any MCP client that supports `stdio` transport can launch the server. Point it at `npx -y temporal-mcp` (or `temporal-mcp` after a global install) and the server handles the rest.
## Tools
### Workflow
| Tool | Description | Stability |
| ------------------------------------- | ------------------------------------------------------------ | --------- |
| `temporal.workflow.list` | List workflows with optional visibility query filters | stable |
| `temporal.workflow.describe` | Get detailed information about a specific workflow execution | stable |
| `temporal.workflow.count` | Count workflows matching a visibility query filter | stable |
| `temporal.workflow.result` | Get the result of a completed workflow execution | stable |
| `temporal.workflow.query` | Query a running workflow using a named query handler | stable |
| `temporal.workflow.history` | Get the event history of a workflow in chronological order | stable |
| `temporal.workflow.history.reverse` | Get event history in reverse chronological order via gRPC | stable |
| `temporal.workflow.history.summarize` | Get a summarized view focusing on key events | stable |
### Schedule
| Tool | Description | Stability |
| ---------------------------------- | ----------------------------------------------------- | --------- |
| `temporal.schedule.list` | List schedules from a Temporal cluster | stable |
| `temporal.schedule.describe` | Get detailed information about a specific schedule | stable |
| `temporal.schedule.matching-times` | Get matching times for a schedule within a time range | stable |
### Infrastructure
| Tool | Description | Stability |
| ----------------------------------- | ----------------------------------------------------------------- | --------- |
| `temporal.task-queue.describe` | Describe a task queue including pollers and backlog status | stable |
| `temporal.task-queue.configuration` | Get task queue configuration including rate limits | stable |
| `temporal.namespace.list` | List all namespaces (self-hosted only) | stable |
| `temporal.namespace.describe` | Get detailed information about a specific namespace | stable |
| `temporal.search-attributes.list` | List search attributes configured for a namespace | stable |
| `temporal.cluster.info` | Get cluster system info including server version and capabilities | stable |
### Worker
| Tool | Description | Stability |
| --------------------------------------------- | ------------------------------------------------------ | ------------ |
| `temporal.worker.versioning-rules` | Get worker versioning rules for a task queue | experimental |
| `temporal.worker.task-reachability` | Check if workers on a task queue can receive tasks | experimental |
| `temporal.worker.deployment.list` | List worker deployments in a namespace | experimental |
| `temporal.worker.deployment.describe` | Describe a specific worker deployment and its versions | experimental |
| `temporal.worker.deployment.version.describe` | Describe a specific version of a worker deployment | experimental |
| `temporal.worker.deployment.reachability` | Check if a worker deployment can still receive tasks | experimental |
### Connection
| Tool | Description | Stability |
| --------------------------- | ---------------------------------------- | --------- |
| `temporal.connection.check` | Check connectivity to a Temporal cluster | stable |
### Documentation
| Tool | Description | Stability |
| -------------- | ---------------------------------------------------------------------------- | --------- |
| `docs.status` | Check the status of the local documentation corpus and curated references | stable |
| `docs.search` | Search the Temporal docs corpus and curated skill references | stable |
| `docs.get` | Get a documentation page or curated reference (`skill/references/core/...`) | stable |
| `docs.refresh` | Refresh the local docs corpus and re-index curated references | stable |
`docs.search` boosts curated reference results 1.5× over raw docs corpus results. `docs.get` accepts paths in the form `skill/references/{category}/{file}.md` to retrieve curated reference files directly.
## Prompts
Four prompt templates are registered and discoverable by any MCP client that supports the prompts capability:
| Prompt | Arguments | Purpose |
| --------------------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------ |
| `temporal-debug-workflow` | `workflowId`, `namespace?`, `profile?` | Step-by-step workflow diagnosis combining live state, event history, and reference lookups |
| `temporal-triage` | `namespace`, `taskQueue?`, `profile?` | Namespace health check: recent failures, worker connectivity, and task queue backlogs |
| `temporal-docs-answer` | `question`, `sdk?` | Answer a Temporal question using the docs corpus and curated references |
| `temporal-safe-mutation` | `workflowId`, `signalName`, `namespace?`, `profile?` | Pre-flight state checks before sending a signal to a running workflow |
Each prompt instructs the agent to call the relevant MCP tools, load the appropriate curated reference files, and produce a structured output. They're designed to be used directly from any MCP client prompt picker.
## Resources
| Resource | URI Template | Format |
| ------------- | ---------------------------------------------- | ------------------ |
| Workflow | `temporal:///{profile}/workflow/{workflowId}` | `application/json` |
| Schedule | `temporal:///{profile}/schedule/{scheduleId}` | `application/json` |
| Task Queue | `temporal:///{profile}/task-queue/{taskQueue}` | `application/json` |
| Namespace | `temporal:///{profile}/namespace/{namespace}` | `application/json` |
| Documentation | `docs:///chunk/{sourcePath}` | `text/markdown` |
## Policy engine
The policy engine controls which tools an agent can invoke. It defaults to `readOnly`, which allows all 28 tools since they are all read-only by design.
### Modes
| Mode | Behavior |
| ----------- | -------------------------------------------------------------------------------------- |
| `readOnly` | Allows all read-risk tools. This is the default. |
| `safeWrite` | Allows read-risk tools and write-risk tools marked as safe (none exist yet). |
| `custom` | Applies no additional risk-based restriction beyond the global filters and allowlists. |
| `unsafe` | Allows everything, but requires the break-glass environment variable to be set. |
### Tool filtering
In any mode, `allowPatterns` and `denyPatterns` can control which tools are available:
```json
{
"policy": {
"mode": "custom",
"allowPatterns": ["temporal.workflow.*", "temporal.schedule.*"],
"denyPatterns": ["temporal.worker.**"]
}
}
```
Deny patterns take precedence over allow patterns.
### Profile and namespace allowlists
Restrict which profiles and namespaces agents can access. An empty list means "allow all":
```json
{
"policy": {
"allowedProfiles": ["local", "staging"],
"allowedNamespaces": ["default", "my-app"]
}
}
```
### Hard read-only lock
Setting `hardReadOnly` to `true` overrides every other policy setting and locks the server to read-only tools, regardless of the configured mode:
```json
{
"policy": {
"hardReadOnly": true
}
}
```
### Break-glass override
The `unsafe` mode requires the `TEMPORAL_MCP_BREAK_GLASS` environment variable to be set. Without it, unsafe tool calls are denied with `BREAK_GLASS_REQUIRED`. This exists as a deliberate speed bump—you have to opt in twice.
## Safety
### Audit logging
Every tool invocation is logged as structured JSON to `stderr`, including the tool name, parameters, policy decision, result status, and duration. Each request gets a unique tracking ID.
### Sensitive field redaction
Tool responses and JSON resource responses are automatically scanned for sensitive fields. Any key matching one of these patterns (case-insensitive) has its value replaced with `[REDACTED]`:
`apiKey`, `password`, `token`, `secret`, `credential`, `authorization`, `cookie`, `session`
### What this server does not do
This server is intentionally limited to observation. It does not:
- Start, signal, cancel, or terminate workflows
- Create, pause, unpause, or delete schedules
- Create or modify namespaces
- Modify task queue configuration
- Perform any cluster administration
- Write to any Temporal state
## Project structure
```
src/
index.ts # Entry point
skill/
SKILL.md # Agent Skills spec entry point
references/
core/ # Language-agnostic reference files (determinism, patterns, etc.)
typescript/ # TypeScript SDK reference files
python/ # Python SDK reference files
go/ # Go SDK reference files
packages/
server/ # MCP server, config, policy, tools, resources, safety
src/
guidance/ # Guidance annotation patterns and post-processing
prompts/ # MCP prompt template registration
temporal/ # Temporal client, gRPC calls, capability matrix
docs/ # Documentation indexing and search (corpus + curated refs)
```
## Maintainer release workflow
### One-time bootstrap publish
1. Authenticate to npm from a maintainer machine (`npm login`).
2. Build and validate:
```bash
bun install --frozen-lockfile
bun run check
bun run build
npm pack --dry-run
```
3. Publish the initial package:
```bash
npm publish --access public
```
4. In npm package settings, add trusted publishing for this repository and `.github/workflows/release.yml`.
Provenance is generated automatically in the tag-driven CI release workflow once OIDC trusted publishing is configured.
### Ongoing releases (tag-driven)
1. Bump the package version and create a `vX.Y.Z` tag:
```bash
bun run release:patch
# or: bun run release:minor
# or: bun run release:major
```
2. Pushing the tag triggers `.github/workflows/release.yml`, which:
- installs dependencies with Bun
- runs `bun run check` and `bun run build`
- publishes to npm using OIDC trusted publishing (no `NPM_TOKEN` secret)
## Development
```bash
bun install
bun run check
# optional coverage report
bun run test:coverage
```
For pull request validation expectations and CI parity details, see [CONTRIBUTING.md](./CONTRIBUTING.md).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues