Skip to content

Latest commit

 

History

History
316 lines (228 loc) · 8.73 KB

File metadata and controls

316 lines (228 loc) · 8.73 KB

ContextForge Bug: Prompts API Accepts Empty Template Field

Bug ID: CONTEXTFORGE-002 Component: ContextForge MCP Gateway - Prompts API Affected Version: v0.8.0, v1.0.0-BETA-1, v1.0.0-BETA-2 (partial) Severity: Low Status: PARTIALLY FIXED (empty string still accepted) Reported: 2025-11-09 Validated: 2026-02-06

Summary

The POST /prompts endpoint accepts prompt creation requests without a template field, allowing prompts to be created with empty/missing templates. This violates the semantic requirement that prompts must have a template to be functional.

Affected Endpoint

POST /prompts

Expected Behavior

When creating a prompt without a template field:

  • The API should reject the request with a 422 Unprocessable Entity error
  • The response should indicate that template is a required field
  • No prompt should be created in the database

A prompt without a template is semantically invalid since:

  • The template defines what the prompt renders
  • Without a template, the prompt cannot function in the MCP protocol
  • The OpenAPI spec describes template as the core content of a prompt

Actual Behavior

When creating a prompt without a template field:

  • The API accepts the request (returns 200 OK) ✓
  • A prompt is created in the database with an empty template
  • No validation error is returned

Reproduction Steps

  1. Send POST request to /prompts with request body:
    {
      "prompt": {
        "name": "test-prompt-without-template"
      }
    }
  2. Request succeeds with 200 OK
  3. Prompt is created with empty/null template field

Expected: 422 Unprocessable Entity with validation error Actual: 200 OK with created prompt

Evidence from Integration Tests

=== RUN   TestPromptsService_InputValidation/create_prompt_without_required_template
    prompts_integration_test.go:498: Expected error when creating prompt without template
    prompts_integration_test.go:501: Correctly rejected prompt without template: <nil>
--- FAIL: TestPromptsService_InputValidation/create_prompt_without_required_template (0.00s)

The test expects an error but receives nil, confirming the API accepts the invalid request.

Root Cause Analysis

OpenAPI Schema

The OpenAPI spec for PromptCreate likely does not mark template as required:

# Expected (should be):
PromptCreate:
  type: object
  required:
    - name
    - template  # ← Should be required
  properties:
    name:
      type: string
    template:
      type: string

Pydantic Model

The Pydantic schema in ContextForge may allow optional template:

File: mcpgateway/schemas.py (presumed)

class PromptCreate(BaseModel):
    name: str
    description: Optional[str] = None
    template: Optional[str] = None  # ← Should not be Optional
    # ...

Database Model

The database schema may allow NULL values for the template column:

File: mcpgateway/models.py (presumed)

class DbPrompt(Base):
    __tablename__ = "prompts"

    template = Column(String, nullable=True)  # ← Should be nullable=False

Comparison with Other Resources

Other resource types properly validate required fields:

  • Tools: Require name field (returns 422 if missing) ✓
  • Resources: Require uri, name, content (returns 422 if missing) ✓
  • Servers: Require name (returns 422 if missing) ✓
  • Prompts: Require name but NOT template

The prompts endpoint is inconsistent with other resource validation patterns.

Impact

Severity: Low

Positive Impacts:

  • Allows creating "draft" prompts that can be filled in later
  • Supports multi-step creation workflows

Negative Impacts:

  • Creates semantically invalid prompts that cannot function
  • Violates principle of least surprise (template seems required)
  • May cause issues when prompts are used in MCP protocol without templates
  • Inconsistent with validation patterns of other resources

Possible Interpretations

Theory 1: Intentional Design

This may be intentional to support workflows like:

  1. Create placeholder prompt with just a name
  2. Update prompt later with template and arguments
  3. Activate prompt when complete

Theory 2: Validation Bug

This may be unintentional due to:

  • Missing validation constraint in Pydantic model
  • Database schema allowing NULL values
  • OpenAPI spec not marking field as required

Recommended Solutions

If Intentional (Feature):

  1. Update Documentation:

    • Clarify that template is optional for draft prompts
    • Document workflow for creating incomplete prompts
    • Add validation that prompts cannot be activated without template
  2. Add State Field:

    class PromptCreate(BaseModel):
        name: str
        template: Optional[str] = None
        state: str = "draft"  # draft, complete, active
  3. Validate on Activation:

    • Prevent toggling to isActive=true if template is empty
    • Return 422 error: "Cannot activate prompt without template"

If Unintentional (Bug):

  1. Update Pydantic Model:

    class PromptCreate(BaseModel):
        name: str
        template: str  # Remove Optional
  2. Update Database Schema:

    template = Column(String, nullable=False)
  3. Update OpenAPI Spec:

    required:
      - name
      - template

SDK Implementation Status

Status: ✅ SDK implementation is correct

Our go-contextforge SDK correctly:

  • Sends the create request with or without template field
  • Handles API response appropriately
  • Does not add artificial client-side validation

The SDK integration test documents expected vs actual behavior, which is valuable for API contract testing.

Workaround

SDK users should:

  1. Always provide template field:

    prompt := &contextforge.PromptCreate{
        Name:     "my-prompt",
        Template: "Hello {{name}}!",  // Always include
    }
  2. Add client-side validation:

    if prompt.Template == "" {
        return errors.New("template is required")
    }
  3. Check created prompts:

    created, _, err := client.Prompts.Create(ctx, prompt, nil)
    if created.Template == "" {
        log.Warn("Prompt created without template")
    }

Related Issues

  • CONTEXTFORGE-001: Prompts toggle returns stale state

References

  • OpenAPI Spec: upstream mcp-context-forge tag schema (no local snapshot maintained in this repo)
  • SDK Integration Test: test/integration/prompts_integration_test.go:490-501

Next Steps

  1. Clarify with ContextForge team if this is intentional or a bug
  2. If intentional: Request documentation update
  3. If bug: Request validation constraint addition
  4. Update SDK tests based on team response
  5. Document behavior in SDK README

Fix Validation (v1.0.0-BETA-1)

Validated: 2026-01-13

The bug is PARTIALLY FIXED in ContextForge v1.0.0-BETA-1.

File: mcpgateway/schemas.py:2046

template: str = Field(..., description="Prompt template text")

The ... in Pydantic Field() means the field is required. However:

Partial Fix Details

Request Status Code Result
Missing template field 422 FIXED - Rejected
Empty template: "" 200 NOT FIXED - Accepted

Evidence

# Missing template - correctly rejected with 422
curl -X POST /prompts -d '{"prompt": {"name": "test"}}'
# Returns 422: "Field required"

# Empty template - incorrectly accepted!
curl -X POST /prompts -d '{"prompt": {"name": "test", "template": ""}}'
# Returns 200: Prompt created with empty template

SDK Impact

The Go SDK's PromptCreate struct has Template string without omitempty, which means it always sends "template": "" when Template is the zero value. This causes the API to accept the request.

SDK Test Status

Integration tests remain skipped because:

  1. The SDK cannot omit the template field (would require *string type)
  2. The API accepts empty template strings
  3. The underlying issue (prompts with empty templates are semantically invalid) persists

Report Generated: 2025-11-09 Tested Against: ContextForge v0.8.0 Fix Validated Against: ContextForge v1.0.0-BETA-2 Reporter: go-contextforge SDK Team


v1.0.0-BETA-2 Revalidation Notes

Validated: 2026-02-06

  • Still Valid? Partially. Missing template is rejected, but template: "" is still accepted.
  • Is it actually a bug? Yes. Accepting an empty prompt template contradicts expected prompt semantics.

Evidence

  • POST /prompts without template now returns validation error.
  • POST /prompts with template: "" still succeeds and creates an effectively empty prompt.
  • Current schema path: mcpgateway/schemas.py and mcpgateway/common/validators.py.