gp

PDDL planning solver exposed as an MCP server and Go library.
gp implements the Graphplan algorithm (Blum & Furst 1997) for
STRIPS planning domains with typing and equality. It ships as:
gp-server -- an MCP server that any AI assistant can call
graphplan -- a Go library for embedding planning in your apps
pddl -- a PDDL parser that feeds into the solver
Background
What is automated planning?
Automated planning finds a sequence of actions that transforms an
initial state into a goal state. You describe what you want -- not
how to get there.
A planning problem has three parts:
- Domain -- the types of objects and actions available
- Problem -- the specific objects, starting state, and goal
- Plan -- the output: a sequence of grounded actions
PDDL: Planning Domain Definition Language
PDDL is the standard input format for planners. A domain defines
predicates (facts about the world) and operators (actions with
preconditions and effects):
(define (domain logistics)
(:requirements :strips :typing)
(:types city cargo rocket)
(:predicates (at ?x - cargo ?c - city)
(in ?x - cargo ?r - rocket)
(rocket-at ?r - rocket ?c - city)
(has-fuel ?r - rocket))
(:action load
:parameters (?c - cargo ?r - rocket ?loc - city)
:precondition (and (at ?c ?loc) (rocket-at ?r ?loc))
:effect (and (not (at ?c ?loc)) (in ?c ?r)))
;; ... more actions
)
A problem specifies objects, initial facts, and goals:
(define (problem deliver)
(:domain logistics)
(:objects r1 - rocket a b - cargo
london paris - city)
(:init (at a london) (at b london)
(rocket-at r1 london) (has-fuel r1))
(:goal (and (at a paris) (at b paris))))
The Graphplan algorithm
Graphplan (Blum & Furst 1997) builds a layered planning graph
alternating between proposition levels and action levels. At each
level it tracks mutual exclusion (mutex) constraints -- pairs of
actions or propositions that cannot coexist.
The algorithm:
- Extend the graph one level (add applicable actions, compute
new mutexes)
- Check if all goals are present and pairwise non-mutex
- Search backward through the graph for a valid plan
- Repeat until a plan is found or the graph levels off with
no solution
Key properties:
- Finds shortest parallel plans (fewest time steps)
- Guaranteed complete -- if a plan exists, it will find it
- Memoization prunes the search space across iterations
Examples
Rocket cargo transport
A rocket must transport two pieces of cargo from London to Paris.
domain.pddl
(define (domain rocket)
(:requirements :strips :typing :equality)
(:types rocket place cargo - object)
(:predicates
(at ?x - object ?y - place)
(in ?c - cargo ?r - rocket)
(has-fuel ?r - rocket))
(:action move
:parameters (?r - rocket ?from - place ?to - place)
:precondition (and
(not (= ?from ?to))
(at ?r ?from)
(has-fuel ?r))
:effect (and
(at ?r ?to)
(not (at ?r ?from))
(not (has-fuel ?r))))
(:action load
:parameters (?r - rocket ?p - place ?c - cargo)
:precondition (and (at ?r ?p) (at ?c ?p))
:effect (and
(in ?c ?r)
(not (at ?c ?p))))
(:action unload
:parameters (?r - rocket ?p - place ?c - cargo)
:precondition (and (at ?r ?p) (in ?c ?r))
:effect (and
(at ?c ?p)
(not (in ?c ?r)))))
problem.pddl
(define (problem rocket-2cargo)
(:domain rocket)
(:objects
r1 - rocket
london paris - place
a b - cargo)
(:init
(at r1 london)
(at a london)
(at b london)
(has-fuel r1))
(:goal (and
(at a paris)
(at b paris))))
Plan (3 time steps):
Step 0: load(r1, london, a) load(r1, london, b)
Step 1: move(r1, london, paris)
Step 2: unload(r1, paris, a) unload(r1, paris, b)
Both cargo items load in parallel, the rocket moves, and both
unload in parallel -- the shortest possible plan.
Blocks world (Sussman anomaly)
The classic AI planning benchmark. Three blocks must be stacked
in order, but the initial configuration forces the planner to
undo partial progress.
domain.pddl
(define (domain blocks-world)
(:requirements :strips :typing)
(:types block - object)
(:predicates
(on ?x - block ?y - block)
(on-table ?x - block)
(clear ?x - block)
(holding ?x - block)
(arm-empty))
(:action pick-up
:parameters (?x - block)
:precondition (and
(clear ?x)
(on-table ?x)
(arm-empty))
:effect (and
(holding ?x)
(not (on-table ?x))
(not (clear ?x))
(not (arm-empty))))
(:action put-down
:parameters (?x - block)
:precondition (holding ?x)
:effect (and
(on-table ?x)
(clear ?x)
(arm-empty)
(not (holding ?x))))
(:action stack
:parameters (?x - block ?y - block)
:precondition (and
(holding ?x)
(clear ?y))
:effect (and
(on ?x ?y)
(clear ?x)
(arm-empty)
(not (holding ?x))
(not (clear ?y))))
(:action unstack
:parameters (?x - block ?y - block)
:precondition (and
(on ?x ?y)
(clear ?x)
(arm-empty))
:effect (and
(holding ?x)
(clear ?y)
(not (on ?x ?y))
(not (clear ?x))
(not (arm-empty)))))
problem.pddl (Sussman anomaly)
(define (problem sussman-anomaly)
(:domain blocks-world)
(:objects a b c - block)
(:init
(on c a)
(on-table a)
(on-table b)
(clear c)
(clear b)
(arm-empty))
(:goal (and
(on a b)
(on b c))))
Initial state: C is on A, A and B are on the table.
Goal: A on B, B on C (stack: A-B-C from top to bottom).
This is the Sussman anomaly -- you cannot achieve both subgoals
independently without undoing one. The planner must unstack C
from A before building the target stack.
Installation
Binary (recommended)
Download the latest release for your platform:
Linux / macOS:
curl -sSL https://raw.githubusercontent.com/byte4ever/gp/master/install.sh | sh
Windows (PowerShell):
irm https://raw.githubusercontent.com/byte4ever/gp/master/install.ps1 | iex
Verify:
gp-server --version
Build from source
go install github.com/byte4ever/gp/cmd/gp-server@latest
Requires Go 1.25+.
MCP Configuration
Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"gp": {
"command": "gp-server"
}
}
}
Claude Code
Add to your project's .mcp.json:
{
"mcpServers": {
"gp": {
"command": "gp-server",
"type": "stdio"
}
}
}
Or run directly:
claude mcp add gp gp-server
Other MCP clients
gp-server speaks MCP over stdio. Point any MCP-compatible client
at the gp-server binary with no arguments.
One-shot solving
| Tool |
Parameters |
Description |
solve_problem |
format (pddl or json), domain, problem |
Parse and solve a planning problem in a single call. |
Session-based solving
For multi-turn workflows where the AI assistant builds up the
domain and problem incrementally:
| Tool |
Parameters |
Description |
create_session |
name |
Create a named planning session. |
set_domain |
session, domain |
Set the PDDL domain on a session. |
set_problem |
session, problem |
Set the PDDL problem on a session. |
solve_session |
session |
Solve the problem stored in a session. |
list_sessions |
-- |
List all active session names. |
delete_session |
session |
Delete a session by name. |
All solve tools return a list of time steps. Actions within the
same step are guaranteed non-interfering and can be executed
in parallel. Steps must be executed sequentially:
{
"solvable": true,
"steps": [
{"time": 0, "actions": ["load(r1, london, a)", "load(r1, london, b)"]},
{"time": 1, "actions": ["move(r1, london, paris)"]},
{"time": 2, "actions": ["unload(r1, paris, a)", "unload(r1, paris, b)"]}
]
}
When no plan exists:
{
"solvable": false,
"error": "no valid plan found"
}
Go Library
Three packages, each usable independently:
go get github.com/byte4ever/gp
graphplan -- solver engine
import "github.com/byte4ever/gp/graphplan"
Build domain and problem structs programmatically, then solve:
solver, err := graphplan.NewSolver(nil)
plan, err := solver.Solve(problem)
See graphplan/README.md for full API.
pddl -- parser
import "github.com/byte4ever/gp/pddl"
Parse PDDL strings into graphplan types:
adapter := pddl.NewAdapter()
domain, err := adapter.ParseDomain(domainPDDL)
problem, err := adapter.ParseProblem(problemPDDL, domain)
Supports :strips, :typing, and :equality requirements.
See pddl/README.md for full API.
mcpserver -- MCP transport
import "github.com/byte4ever/gp/mcpserver"
Embed the MCP server in your own application:
srv, err := mcpserver.NewServer(cfg, solver, adapter, adapter)
srv.Run()
See mcpserver/README.md for full API.
Project Structure
cmd/gp-server/ Entrypoint binary
graphplan/ Solver engine (Graphplan algorithm)
pddl/ PDDL parser and AST-to-graphplan converter
mcpserver/ MCP server wiring and tool handlers
testdata/ PDDL test fixtures
install.sh Linux/macOS installer
install.ps1 Windows installer
.goreleaser.yaml Cross-platform release config
License
MIT