Skip to main content
Glama

Prompt Lab MCP Server

Prompt optimization loops and regression test suites for Claude Code, with a companion web UI.

The agent runs inside your Claude Code session and owns all LLM work — scoring responses, proposing improved prompts, applying suggestions. The server holds workspace state and keeps the agent and the Prompt Lab UI in sync.


Quick start

Copy mcp-connect.json from this repo into your project as .mcp.json:

{
  "mcpServers": {
    "prompt-lab": {
      "type": "http",
      "url": "https://prompt-lab-mcp.up.railway.app/mcp"
    }
  }
}

Claude Code connects automatically on next start. Verify with /mcp.


Related MCP server: Session Buddy

Example session

# 1. Open a workspace — agent shares the UI URL
start_web_app()
→ "Open https://prompt-lab-mcp.vercel.app?s=abc123 to follow along."

# 2. Register an API key
register_api_key(workspaceId, "sk-ant-...")

# 3. Set a system prompt and a test case
set_system_prompt(workspaceId, "You are a concise customer support agent...")
add_test_cases(workspaceId, [{
  query: "How do I reset my password?",
  targetAnswer: "Click 'Forgot password' on the login page and follow the email link."
}])

# 4. Run the optimization loop
loop_optimization(workspaceId, threshold=85)
→ Iteration 1 — score 58: response too long, no mention of email link
→ Iteration 2 — score 74: better, but missing the exact step
→ Iteration 3 — score 91: SUCCESS — prompt updated to require step-by-step answers

The UI shows each iteration's score, the agent's reasoning, and the revised system prompt in real time.


How it works

Prompt Lab UI (github.com/jurek-f/prompt-lab)
  ↕  HTTP
Prompt Lab MCP Server (Railway)
  ↕  MCP
Claude Code (your machine)

API keys

API keys are never stored in the MCP server config. Instead, pass them to Claude Code as environment variables — the agent reads them and registers them with the server at the start of each session using register_api_key.

Set the key(s) for the provider(s) you want to use. The agent auto-detects the provider from the key prefix when calling register_api_key.

If they're already in your system environment, Claude Code inherits them automatically — nothing else to do. Otherwise add them to ~/.claude/env or your shell profile:

ANTHROPIC_API_KEY=sk-ant-...
GEMINI_API_KEY=AIza...
OPENAI_API_KEY=sk-...

MCP tools

Setup

Tool

Description

start_web_app(workspaceId?)

Creates a workspace and returns the Prompt Lab UI URL.

register_api_key(workspaceId, apiKey, provider?)

Registers an API key for test runs. Provider is auto-detected from the key prefix.

list_models(workspaceId)

Lists available models based on registered keys.

set_test_model(workspaceId, model)

Sets the model for test runs. Syncs to the UI model selector.

delete_session(workspaceId)

Deletes a workspace and all its state. Irreversible.

Templates

Templates are global and appear in the UI dropdowns as soon as they are pushed.

Tool

Description

save_template(name, testCases)

Saves a test suite template. Appears in the UI "Load test suite…" dropdown.

save_system_prompt_template(name, content)

Saves a system prompt template. Appears in the UI "Load template…" dropdown.

Workspace state

Tool

Description

get_workspace_state(workspaceId)

Reads the full workspace: system prompt, test cases, results, suggestions, model.

set_system_prompt(workspaceId, systemPrompt)

Sets the system prompt without incrementing the iteration counter.

add_test_cases(workspaceId, testCases, replace?)

Adds test cases. replace=true overwrites all existing ones.

post_test_result(workspaceId, testCaseId, response, score, reasoning, model)

Stores one scored test result.

post_prompt_suggestion(workspaceId, prompt, reasoning, expectedGain?)

Queues a revised prompt for review in the UI.

apply_suggestion(workspaceId, suggestionId)

Applies a pending suggestion and increments the iteration counter.

get_regression_status(workspaceId, threshold?)

Pass/fail summary across all test cases for the current system prompt.

Optimization

Requires a workspace with at least one test case.

Tool

Description

start_optimization_session(workspaceId, threshold?, maxIterations?)

Single pass — scores test cases, posts one suggestion, then waits for user review in the UI.

loop_optimization(workspaceId, threshold?, maxIterations?)

Automated loop — iterates until all scores meet the threshold or max iterations is reached.

Regression

Tool

Description

run_regression_testsuite(workspaceId, threshold?)

Single pass — scores all test cases, no prompt changes.

loop_regression(workspaceId, threshold?)

Automated loop — repeats until every individual score meets the threshold. A high average that masks one failing case is not a pass.

Archive

Tool

Description

pull_ui_history(workspaceId)

Fetches all session summaries and regression runs pushed by the UI.


Self-hosting

Deploy to Railway and set these environment variables:

Variable

Description

UPSTASH_REDIS_REST_URL

Upstash Redis URL for persistence

UPSTASH_REDIS_REST_TOKEN

Upstash Redis token

PROMPT_LAB_UI_URL

URL of your Prompt Lab UI deployment

npm install
npm run dev    # starts on :3000

MCP endpoint: http://localhost:3000/mcp


License

MIT — see LICENSE.

© 2026 Jurek Föllmer

Available Tools

19 tools
add_test_casesA

Add test cases to this workspace.

Set replace: true to clear the existing suite and load a fresh one. Set replace: false (default) to append to the existing suite.

Each test case needs at least a query. targetAnswer is required for scoring. Omit targetAnswer only for exploratory runs where you score manually.

Inputs: workspaceId (required), testCases (required), replace.

apply_suggestionA

Apply a pending suggestion: sets it as the active system prompt and increments the iteration counter.

Only call in fully automated loop mode (loop_optimization, loop_regression). In gated mode, wait for the user to approve via the UI.

Inputs: workspaceId (required), suggestionId (required).

delete_sessionB

Delete a workspace and all its state (test cases, results, suggestions, API keys). Irreversible.

Inputs: workspaceId (required).

get_regression_statusB

Pass/fail summary across all test cases for the current system prompt.

Call after running all test cases to decide: is the prompt good enough, or improve further? A test case passes if its most recent score >= threshold (default 70).

Inputs: workspaceId (required), threshold.

get_workspace_stateA

Read the full current state of a workspace.

Returns: system prompt, test cases, test results, suggestions, iteration counter, optimization goal, available models, selected model, and active query/target.

Call at the start of each session to recover state after a context break. Also call before running tests to get the latest test case IDs.

Inputs: workspaceId (required).

list_modelsB

Register available AI models and API keys for this workspace.

Call once after start_web_app. Scan your environment for API keys and Ollama:

  1. process.env.ANTHROPIC_API_KEY → add claude-haiku-4-5-20251001, claude-sonnet-4-6, claude-opus-4-8

  2. process.env.GEMINI_API_KEY → add gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro

  3. process.env.OPENAI_API_KEY → add gpt-4o-mini, gpt-4o

  4. Ollama: fetch (process.env.OLLAMA_URL ?? "http://localhost:11434") + "/api/tags" → add each model.name; catch errors silently

Default model priority (first available wins): gemini-2.5-flash-lite → claude-haiku-4-5-20251001 → gpt-4o-mini

Inputs: workspaceId (required), models (required), defaultModel, anthropicApiKey, +2 more.

loop_optimizationA

Run the full optimization loop until the threshold is met or max iterations reached.

Like start_optimization_session but auto-applies each suggestion and repeats.

Prerequisites: same as start_optimization_session.

Loop:

  1. Run all test cases, score responses, call post_test_result for each.

  2. Call get_regression_status.

  3. If ALL scores >= threshold AND iteration >= 1 → SUCCESS.

  4. If iteration >= maxIterations → EXHAUSTED. Report best result.

  5. Analyse failures, write improved prompt (targeted — fix pattern, keep what works).

  6. Call post_prompt_suggestion then apply_suggestion (auto authorised in loop mode).

  7. Go to 1.

Do NOT stop after the first pass because it is passing — first pass is a baseline. Always run at least one improvement cycle.

After the loop: call pull_ui_history, save optimization results locally, call save_system_prompt_template with the best prompt found.

Inputs: workspaceId (required), threshold, maxIterations.

loop_regressionA

Run the full regression loop: test all cases → score → improve → repeat.

Stops when BOTH conditions are met:

  • Overall pass rate >= threshold

  • Every individual test case score >= threshold Or when max iterations are exhausted.

Loop:

  1. Run all test cases, score responses, call post_test_result for each.

  2. Call get_regression_status.

  3. If pass rate >= threshold AND all individual scores >= threshold → SUCCESS.

  4. If iteration >= maxIterations → EXHAUSTED. Report best result.

  5. Analyse failures, write improved prompt, call post_prompt_suggestion + apply_suggestion.

  6. Go to 1.

After the loop: call pull_ui_history and save results locally.

Inputs: workspaceId (required), threshold, maxIterations.

post_prompt_suggestionA

Queue a revised system prompt for the user to review.

Always explain in reasoning:

  • which test cases were failing and why

  • what specific change you made to the prompt

  • why you expect this change to fix those cases

In gated mode (start_optimization_session): user reviews in UI, then approves or rejects. In loop mode (loop_optimization, loop_regression): call apply_suggestion immediately after.

Inputs: workspaceId (required), prompt (required), reasoning (required), expectedGain.

post_test_resultA

Store the scored result of one test case run.

Call after you run a test case against the model and evaluate the response. This makes the result visible in the UI and is used by get_regression_status.

Score 0–100 using this scale: 90–100: Correct, complete, well-structured — exceeds target. 70–89: Correct and complete — minor gaps or style issues. 50–69: Partially correct — key points present but missing important details. 30–49: Mostly wrong — one or two relevant points but fundamentally off. 0–29: Completely wrong, off-topic, or refused.

Inputs: workspaceId (required), testCaseId (required), response (required), score (required), +2 more.

pull_ui_historyA

Fetch all history entries the UI has pushed to this workspace.

The UI auto-pushes after every session summary ("Summarize & new") and every regression run. This gives you a record of what the user did in the UI between agent calls.

ALWAYS save the response to a local file: prompt-lab/workspaces//_ui_history.json

Inputs: workspaceId (required).

register_api_keyA

Register a provider API key for this workspace.

Use this when you need to register a key that was not passed to start_web_app. Specify provider explicitly: anthropic | google | openai.

Inputs: workspaceId (required), apiKey (required), provider (required).

run_regression_testsuiteA

Run all test cases against the current system prompt. Single pass — does not auto-improve.

Use this to verify an already-good prompt still passes all test cases. For automatic improvement loops, use loop_regression.

Steps to follow after this call:

  1. Run each test case against the model, score the response, call post_test_result.

  2. Call get_regression_status to see pass/fail summary.

  3. Optionally: post_prompt_suggestion with an improvement (user reviews).

Inputs: workspaceId (required), threshold.

save_system_prompt_templateA

Save a named system prompt template so it appears in the UI "Load template…" dropdown.

Call at session startup for every .txt file in prompt-lab/system-prompts/: save_system_prompt_template(name=, content=)

Also call after a successful optimization loop to preserve the best prompt found.

Templates persist in Redis. Saving with the same name replaces the previous version.

Inputs: name (required), content (required).

save_templateA

Save a named test suite template so it appears in the UI "Load test suite…" dropdown.

Call at session startup for every .json file in prompt-lab/templates/: save_template(name=<file.name>, testCases=<file.testCases>)

Template format (matches what the UI exports as a downloadable JSON): { "name": "suite-name", "savedAt": "...", "testCases": [{ "label"?, "query", "targetAnswer"?, "passThreshold"?, "queryType"? }] }

Templates persist in Redis. Saving with the same name replaces the previous version.

Inputs: name (required), testCases (required).

set_system_promptA

Set or update the system prompt for this workspace.

Does NOT increment the iteration counter — use this for initial setup or manual overrides. To record an optimization step, use apply_suggestion.

Load the current prompt from current.json or ask the user before overwriting.

Inputs: workspaceId (required), systemPrompt (required).

set_test_modelB

Switch the model used for test cases in this workspace. Updates the UI model selector.

Inputs: workspaceId (required), model (required).

start_optimization_sessionA

Run one optimization pass on an existing workspace.

Prerequisites (do these first):

  1. start_web_app → workspace URL + ID

  2. set_system_prompt → starting prompt

  3. add_test_cases → at least one case with targetAnswer

What this does:

  1. Read system prompt and test cases from get_workspace_state.

  2. Run each test case against the model (write + execute a temp Node.js script).

  3. Score each response vs targetAnswer (LLM-as-judge, 0–100), call post_test_result.

  4. Analyse failures, write improved prompt, call post_prompt_suggestion.

  5. Present the suggestion — do NOT auto-apply. User reviews in the UI.

This is one iteration. After the user approves or rejects the suggestion, call start_optimization_session again or switch to loop_optimization.

Inputs: workspaceId (required), threshold, maxIterations.

start_web_appA

Open the prompt lab web UI. Returns the URL for the browser.

If no workspaceId is given, creates a new empty workspace. If workspaceId is given, connects to that workspace (must exist).

Always pass your environment API keys — they enable the UI Send button. Check each env var and pass it if set: anthropicApiKey: process.env.ANTHROPIC_API_KEY geminiApiKey: process.env.GEMINI_API_KEY openaiApiKey: process.env.OPENAI_API_KEY

After returning the URL, call list_models to register available models. Then set_system_prompt and add_test_cases before running optimization.

Inputs: workspaceId, label, anthropicApiKey, geminiApiKey, +1 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.9/5.0

    Scored across 19 tools

    Disambiguation4/5

    Most tools have distinct purposes, but pairs like loop_optimization/loop_regression and start_optimization_session/loop_optimization could be confused. Descriptions help differentiate, but the distinction between single-pass and loop modes might not be immediately clear.

    Naming Consistency5/5

    All tool names follow a consistent verb_noun pattern in snake_case (e.g., add_test_cases, set_system_prompt). No mixing of conventions or ambiguous names.

    Tool Count5/5

    19 tools cover the full prompt lab workflow without excess. Each tool addresses a distinct step in setup, testing, optimization, and management, making the count appropriate for the server's scope.

    Completeness4/5

    The tool set covers the main workflow end-to-end, but lacks granular control like editing or deleting individual test cases or canceling loops. Minor gaps, but core functionality is present.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers