API Reference¶
Ploidy exposes MCP tools for debate orchestration over the Streamable HTTP transport at http://localhost:8765/mcp.
Tools Overview¶
| Tool | Purpose | Read-only | Destructive | Idempotent |
|---|---|---|---|---|
debate_start | Create a new debate | No | Yes | No |
debate_join | Join an existing debate | No | No | No |
debate_position | Submit a position statement | No | No | No |
debate_challenge | Submit a challenge to another position | No | No | No |
debate_converge | Trigger convergence analysis | No | No | No |
debate_status | Get current debate state | Yes | No | Yes |
debate_cancel | Cancel an in-progress debate | No | Yes | Yes |
debate_delete | Delete a debate permanently | No | Yes | Yes |
debate_history | List past debates | Yes | No | Yes |
debate_auto | Run a full debate automatically | No | Yes | No |
debate_review | Review and resume a paused auto-debate (HITL) | No | No | No |
debate_start¶
Begin a new debate session with a decision prompt. Creates a debate record and the initial Experienced session.
Parameters¶
| Parameter | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | The decision question to debate. |
context_documents | list[string] | No | Optional documents to provide to the Deep session. These are stored for the record but NOT shown to the Fresh session. |
Returns¶
{
"debate_id": "a1b2c3d4e5f6",
"session_id": "a1b2c3d4e5f6-exp8f2a",
"role": "experienced",
"phase": "independent",
"prompt": "Should we use monorepo or polyrepo?"
}
Annotations¶
destructiveHint: true-- Creates a new debate recordreadOnlyHint: falseidempotentHint: false-- Each call creates a new debate
Example¶
User: Use debate_start to debate "Should we migrate our REST API to GraphQL?"
Tool call: debate_start(
prompt="Should we migrate our REST API to GraphQL?",
context_documents=["We have 47 REST endpoints serving 3 mobile clients and 1 web app."]
)
debate_join¶
Join an existing debate as a fresh or semi_fresh session.
Parameters¶
| Parameter | Type | Required | Description |
|---|---|---|---|
debate_id | string | Yes | Debate identifier returned by debate_start. |
role | string | No | fresh or semi_fresh. Default: fresh. |
delivery_mode | string | No | none, passive, or active. Default: none. |
Returns¶
{
"debate_id": "a1b2c3d4e5f6",
"session_id": "a1b2c3d4e5f6-fresh-123abc",
"role": "fresh",
"delivery_mode": "none",
"phase": "independent",
"prompt": "Should we use monorepo or polyrepo?"
}
debate_position¶
Submit a position from a session. Records a session's stance on the debate prompt during the POSITION phase.
Parameters¶
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id | string | Yes | The session submitting the position. |
content | string | Yes | The position statement. Should be specific and actionable. |
Returns¶
{
"session_id": "debate-a1b2c3d4-exp8f2a",
"phase": "position",
"status": "recorded",
"content_length": 342
}
Annotations¶
destructiveHint: falsereadOnlyHint: falseidempotentHint: false-- Each submission is recorded as a new message
Example¶
Tool call: debate_position(
session_id="debate-a1b2c3d4-exp8f2a",
content="We should keep REST. Our 47 endpoints are well-documented, our mobile team
knows the patterns, and the migration cost outweighs the benefits for our
current team size of 4 engineers."
)
debate_challenge¶
Submit a challenge to another session's position. Records a session's critique during the CHALLENGE phase.
Parameters¶
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id | string | Yes | The session submitting the challenge. |
content | string | Yes | The challenge or critique text. |
action | string | No | Semantic action classifying this message's intent. Default: "challenge". |
Semantic Actions¶
| Action | Meaning |
|---|---|
agree | "I reached the same conclusion independently." |
challenge | "I disagree with this position, here's why." |
propose_alternative | "Neither position is right -- consider this third option." |
synthesize | "Both positions have merit -- here's a synthesis." |
Returns¶
{
"session_id": "debate-a1b2c3d4-fre3b7c",
"phase": "challenge",
"action": "challenge",
"status": "recorded",
"content_length": 289
}
Annotations¶
destructiveHint: falsereadOnlyHint: falseidempotentHint: false
Example¶
Tool call: debate_challenge(
session_id="debate-a1b2c3d4-fre3b7c",
content="The 'well-documented' claim assumes documentation stays current.
GraphQL's self-documenting schema eliminates this maintenance burden.
Also, 3 mobile clients making different data requests is exactly the
over-fetching problem GraphQL solves.",
action="challenge"
)
debate_converge¶
Trigger convergence analysis for a debate. Runs the convergence engine on the debate transcript and produces a structured synthesis of agreements and disagreements.
Parameters¶
| Parameter | Type | Required | Description |
|---|---|---|---|
debate_id | string | Yes | The debate to analyze. |
Returns¶
{
"debate_id": "debate-a1b2c3d4",
"synthesis": "Keep REST for existing endpoints. Introduce GraphQL as a new
gateway layer for mobile clients, allowing gradual migration
without disrupting the current API.",
"confidence": 0.72,
"points": [
{
"category": "agreement",
"summary": "Migration cost is non-trivial",
"session_a_view": "47 endpoints is too many to migrate at once",
"session_b_view": "Full migration would be costly regardless of endpoint count",
"resolution": "Both agree migration should be incremental if done at all"
},
{
"category": "productive_disagreement",
"summary": "Documentation maintenance burden",
"session_a_view": "REST endpoints are well-documented",
"session_b_view": "Documentation requires ongoing maintenance; schemas are self-documenting",
"resolution": "Valid concern -- GraphQL schema as documentation source of truth"
}
]
}
Annotations¶
destructiveHint: falsereadOnlyHint: falseidempotentHint: falseopenWorldHint: false-- Analysis is based only on the debate transcript
Example¶
debate_status¶
Get current state of a debate. Returns phase, session info, and message counts.
Parameters¶
| Parameter | Type | Required | Description |
|---|---|---|---|
debate_id | string | Yes | The debate to inspect. |
Returns¶
{
"debate_id": "debate-a1b2c3d4",
"phase": "challenge",
"message_count": 4,
"sessions": [
{
"session_id": "debate-a1b2c3d4-exp8f2a",
"role": "experienced"
},
{
"session_id": "debate-a1b2c3d4-fre3b7c",
"role": "fresh"
}
],
"messages": {
"position": [],
"challenge": []
}
}
Annotations¶
readOnlyHint: true-- Does not modify debate statedestructiveHint: falseidempotentHint: true-- Same input always returns current state
debate_history¶
Retrieve past debates and their outcomes. Lists recent debates with their status and convergence results.
Parameters¶
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | integer | No | Maximum number of debates to return. Default: 50. |
Returns¶
{
"debates": [
{
"id": "a1b2c3d4e5f6",
"prompt": "Should we use monorepo or polyrepo?",
"status": "complete",
"created_at": "2026-03-19 08:00:00",
"updated_at": "2026-03-19 08:01:10"
}
],
"total": 1,
"limit": 50
}
debate_auto¶
Run a complete debate automatically using an OpenAI-compatible API backend.
The server generates:
- an Experienced position using
context_documents - a Fresh or Semi-Fresh position
- challenge messages from both sides
- convergence analysis
Parameters¶
| Parameter | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | The decision prompt. |
context_documents | list[string] | No | Context for the Experienced side. |
fresh_role | string | No | fresh or semi_fresh. Default: fresh. |
delivery_mode | string | No | none, passive, or active. Default: none. |
Constraints¶
fresh_role="fresh"requiresdelivery_mode="none"fresh_role="semi_fresh"requiresdelivery_mode="passive"ordelivery_mode="active"- requires
PLOIDY_API_BASE_URLand compatible credentials
Returns¶
{
"debate_id": "a1b2c3d4e5f6",
"phase": "complete",
"mode": "auto",
"fresh_role": "fresh",
"delivery_mode": "none",
"synthesis": "Use a monorepo for the shared auth layer but isolate deployment boundaries.",
"confidence": 0.5,
"meta_analysis": null,
"points": [
{
"category": "productive_disagreement",
"summary": "Deployment coupling risk",
"resolution": null
}
]
}
{
"debates": [
{
"id": "debate-a1b2c3d4",
"prompt": "Should we migrate our REST API to GraphQL?",
"status": "complete",
"created_at": "2026-03-15T14:30:00",
"updated_at": "2026-03-15T14:35:22"
}
],
"total": 1,
"limit": 50
}
Annotations¶
readOnlyHint: truedestructiveHint: falseidempotentHint: true
Data Types¶
DebatePhase¶
The debate protocol progresses through five phases:
| Phase | Description |
|---|---|
independent | Sessions analyze the prompt independently |
position | Sessions declare their stances |
challenge | Sessions critique each other's positions |
convergence | Convergence engine synthesizes the debate |
complete | Debate concluded, result available |
SemanticAction¶
Actions that classify the intent of a challenge message:
| Action | Description |
|---|---|
agree | Independent agreement with the other position |
challenge | Disagreement with specific reasoning |
propose_alternative | Neither position is adequate; a third option is proposed |
synthesize | Both positions have merit; a synthesis is offered |
ConvergencePoint¶
A single point in the convergence analysis:
| Field | Type | Description |
|---|---|---|
category | string | One of agreement, productive_disagreement, irreducible |
summary | string | Brief description of the point |
session_a_view | string | The Deep session's perspective |
session_b_view | string | The Fresh session's perspective |
resolution | string \| null | Synthesized resolution, if any |