veyron/runtimes/google/ipc: new Serve method to replace Register+Publish.

Change-Id: Icc69645e753a3e84c5d87a3e9d2d4abd36275fff
diff --git a/examples/bank/pbankd/main.go b/examples/bank/pbankd/main.go
index 9e27a8b..07d0e4f 100644
--- a/examples/bank/pbankd/main.go
+++ b/examples/bank/pbankd/main.go
@@ -414,10 +414,7 @@
 	bankAuth := security.NewACLAuthorizer(security.ACL{security.AllPrincipals: security.LabelSet(security.ReadLabel | security.WriteLabel)})
 	bankAccountAuth := AccountAuthorizer(runtime.Identity().PublicID().Names()[0] + SUFFIX_REGEXP)
 
-	// Register the "bank" prefix with a bank dispatcher.
-	if err := s.Register("bank", newBankDispatcher(bankServer, bankAccountServer, bankAuth, bankAccountAuth)); err != nil {
-		vlog.Fatal("error registering service: ", err)
-	}
+	dispatcher := newBankDispatcher(bankServer, bankAccountServer, bankAuth, bankAccountAuth)
 
 	// Create an endpoint and begin listening.
 	endpoint, err := s.Listen("tcp", "127.0.0.1:0")
@@ -428,10 +425,10 @@
 	}
 
 	// Publish the service in the mount table.
-	mountName := "veyron"
+	mountName := "veyron/bank"
 	fmt.Printf("Mounting bank on %s, endpoint /%s\n", mountName, endpoint)
-	if err := s.Publish(mountName); err != nil {
-		vlog.Fatal("s.Publish() failed: ", err)
+	if err := s.Serve(mountName, dispatcher); err != nil {
+		vlog.Fatal("s.Serve() failed: ", err)
 	}
 
 	// Wait forever.
diff --git a/examples/boxes/signallingserver/main.go b/examples/boxes/signallingserver/main.go
index dc413e8..04536d4 100644
--- a/examples/boxes/signallingserver/main.go
+++ b/examples/boxes/signallingserver/main.go
@@ -41,9 +41,6 @@
 
 	var boxApp boxAppEndpoint
 	srv := boxes.NewServerBoxSignalling(&boxApp)
-	if err := s.Register(signallingServiceName, ipc.SoloDispatcher(srv, nil)); err != nil {
-		log.Fatal("failed to Register signalling service: ", err)
-	}
 
 	// Create an endpoint and begin listening.
 	if endPt, err := s.Listen("tcp", signallingServicePort); err == nil {
@@ -52,8 +49,8 @@
 		log.Fatal("failed Listen: ", err)
 	}
 
-	if err := s.Publish("/" + signallingServiceName); err != nil {
-		log.Fatal("failed Publish:", err)
+	if err := s.Serve("/"+signallingServiceName, ipc.SoloDispatcher(srv, nil)); err != nil {
+		log.Fatal("failed Serve:", err)
 	}
 
 	<-signals.ShutdownOnSignals()
diff --git a/examples/fortune/fortune/main.go b/examples/fortune/fortune/main.go
index 96bc2bb..9076151 100644
--- a/examples/fortune/fortune/main.go
+++ b/examples/fortune/fortune/main.go
@@ -29,7 +29,7 @@
 
 	// Construct a new stub that binds to serverEndpoint without
 	// using the name service
-	s, err := fortune.BindFortune(naming.JoinAddressName(*address, "//fortune"))
+	s, err := fortune.BindFortune(naming.JoinAddressName(*address, ""))
 	if err != nil {
 		log.Fatal("error binding to server: ", err)
 	}
diff --git a/examples/fortune/fortuned/main.go b/examples/fortune/fortuned/main.go
index 3e812ac..09e43a7 100644
--- a/examples/fortune/fortuned/main.go
+++ b/examples/fortune/fortuned/main.go
@@ -56,11 +56,6 @@
 	// Create the fortune server stub.
 	serverFortune := fortune.NewServerFortune(newFortuned())
 
-	// Register the "fortune" prefix with a fortune dispatcher.
-	if err := s.Register("fortune", ipc.SoloDispatcher(serverFortune, vflag.NewAuthorizerOrDie())); err != nil {
-		log.Fatal("error registering service: ", err)
-	}
-
 	// Create an endpoint and begin listening.
 	if endpoint, err := s.Listen("tcp", "127.0.0.1:0"); err == nil {
 		fmt.Printf("Listening at: %v\n", endpoint)
@@ -68,6 +63,12 @@
 		log.Fatal("error listening to service: ", err)
 	}
 
+	// Serve the fortune dispatcher, but don't publish its existence
+	// to a mount table.
+	if err := s.Serve("", ipc.SoloDispatcher(serverFortune, vflag.NewAuthorizerOrDie())); err != nil {
+		log.Fatal("error serving service: ", err)
+	}
+
 	// Wait forever.
 	<-signals.ShutdownOnSignals()
 }
diff --git a/examples/inspector/inspector/main.go b/examples/inspector/inspector/main.go
index 470044a..cc8bc1e 100644
--- a/examples/inspector/inspector/main.go
+++ b/examples/inspector/inspector/main.go
@@ -58,7 +58,7 @@
 			return
 		}
 	}
-	fmt.Fprintf(os.Stderr, "need to use a one of '.../stubbed/...' or '.../stubless/...'\n")
+	fmt.Fprintf(os.Stderr, "need to use one of '.../stubbed/...' or '.../stubless/...'\n")
 	os.Exit(1)
 }
 
@@ -117,9 +117,13 @@
 	} else {
 		ls(call)
 	}
-	if err := call.Finish(); err != nil && err != io.EOF {
+	var verr error
+	if err := call.Finish(&verr); err != nil && err != io.EOF {
 		vlog.Fatalf("%q", err)
 	}
+	if verr != nil {
+		vlog.Fatalf("%q", verr)
+	}
 }
 
 // streamNames and streamDetails are idiomatic for use with stubs
diff --git a/examples/inspector/inspector/test.sh b/examples/inspector/inspector/test.sh
new file mode 100644
index 0000000..4805640
--- /dev/null
+++ b/examples/inspector/inspector/test.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+tl=$(git rev-parse --show-toplevel)
+
+go=$tl/scripts/build/go
+
+script=$0
+
+cleanup() {
+	code=$1; msg=$2; shift; shift
+	[ "$*" != "" ] && echo "cleanup: $*"
+	rm -f .ep
+	kill $pid > /dev/null 2>&1
+	killall inspectord > /dev/null 2>&1
+	echo $script $msg
+	return $code
+}
+
+bd=$(dirname $0)
+echo "Build directory:" $bd
+
+(cd $bd; $go build .) || exit 1
+(cd $bd/../inspectord; $go build .) || exit 1
+
+(cd $bd/../inspectord; ./inspectord) 2> /dev/null > .ep &
+pid=$!
+
+for i in 1 2 3 4; do
+	ep=$(cat .ep)
+	if [ "$ep" != "" ]; then
+		break
+	fi
+	sleep $i
+done
+
+[ ! $ep ] && cleanup 0 FAIL "no server" && exit 1
+
+$bd/inspector --service /$ep/stubbed/files -glob='m*' || cleanup 1 FAIL "stubbed/files" || exit 1
+$bd/inspector --service /$ep/stubless/files -glob='m*'|| cleanup 1 FAIL "stubless/files" || exit 1
+
+cleanup 0 PASS && exit 0
diff --git a/examples/inspector/inspectord/main.go b/examples/inspector/inspectord/main.go
index 662ee29..cd6c84f 100644
--- a/examples/inspector/inspectord/main.go
+++ b/examples/inspector/inspectord/main.go
@@ -5,7 +5,6 @@
 	"os"
 
 	"veyron2"
-	"veyron2/ipc"
 	"veyron2/rt"
 	"veyron2/vlog"
 )
@@ -22,35 +21,20 @@
 	if err != nil {
 		log.Fatalf("failed to init runtime: %q", err)
 	}
+	hostname, _ := os.Hostname()
 	server, err := r.NewServer()
 	if err != nil {
 		log.Fatalf("failed to create server: %q", err)
 	}
-	for stubbed, prefix := range map[bool]string{true: "stubbed/", false: "stubless/"} {
-		servers := []struct {
-			name string
-			disp ipc.Dispatcher
-		}{
-			{"files", NewFileSvc(stubbed)},
-			{"proc", NewProcSvc(stubbed)},
-			{"devices", NewDeviceSvc(stubbed)},
-		}
-		for _, s := range servers {
-			if err := server.Register(prefix+s.name, s.disp); err != nil {
-				log.Fatalf("failed to register %q: %q\n", s.name, err)
-			}
-		}
-	}
 	ep, err := server.Listen("tcp", "localhost:0")
 	if err != nil {
 		log.Fatalf("listen failed: %q", err)
 	}
-	hostname, _ := os.Hostname()
-	if err := server.Publish(hostname); err != nil {
-		log.Fatalf("publish of %q failed: %q", hostname, err)
+	if err := server.Serve(hostname, &dispatcher{}); err != nil {
+		log.Fatalf("failed to register %q: %q\n", hostname, err)
 	}
+	defer server.Stop()
 	fmt.Printf("%s\n", ep)
-
 	// Wait forever.
 	done := make(chan struct{})
 	<-done
diff --git a/examples/inspector/inspectord/services.go b/examples/inspector/inspectord/services.go
index 1a087a6..0a936bc 100644
--- a/examples/inspector/inspectord/services.go
+++ b/examples/inspector/inspectord/services.go
@@ -5,6 +5,7 @@
 	"io"
 	"os"
 	"path/filepath"
+	"strings"
 	"time"
 
 	"veyron2/ipc"
@@ -24,10 +25,7 @@
 
 // Dispatchers create servers, based on the names used. Dispatchers
 // create stubbed or stubless servers.
-type dispatcher struct {
-	service serviceType
-	stubbed bool
-}
+type dispatcher struct{}
 
 // A service represents one of the file, proc or device service
 type server struct {
@@ -138,12 +136,6 @@
 	return nil
 }
 
-// List is a stubless server method
-func (s *server) List(call ipc.ServerCall, glob string, details bool) error {
-	log.Infof("List: %q details %t", glob, details)
-	return s.ls(glob, details, &stublessServer{call})
-}
-
 // Ls is a stubbed server method
 func (s *server) Ls(context ipc.ServerContext, Glob string, Stream inspector.InspectorServiceLsStream) error {
 	log.Infof("Ls %q", Glob)
@@ -156,39 +148,52 @@
 	return s.ls(Glob, true, &stubbedServer{context: context, details: Stream})
 }
 
+type stubwrapper struct {
+	s *server
+}
+
+// List is a stubless server method
+func (s *stubwrapper) List(call ipc.ServerCall, glob string, details bool) error {
+	log.Infof("List: %q details %t", glob, details)
+	return s.s.ls(glob, details, &stublessServer{call})
+}
+
 func (d *dispatcher) Lookup(suffix string) (ipc.Invoker, security.Authorizer, error) {
-	s := &server{service: d.service, suffix: suffix}
-	switch d.service {
-	case fileSvc:
-		cwd, err := os.Getwd()
-		if err != nil {
-			return nil, nil, err
-		}
+	s := &server{}
+	cwd, err := os.Getwd()
+	if err != nil {
+		return nil, nil, err
+	}
+	switch {
+	case strings.HasPrefix(suffix, "stubbed/files"):
 		s.root = cwd
-	case deviceSvc:
-		s.root = "/dev"
-	case procSvc:
-		s.root = "/proc"
-	}
-	if d.stubbed {
+		s.suffix = strings.TrimPrefix(suffix, "stubbed/files")
 		return ipc.ReflectInvoker(inspector.NewServerInspector(s)), nil, nil
-	} else {
+	case strings.HasPrefix(suffix, "stubbed/proc"):
+		s.root = "/proc"
+		s.suffix = strings.TrimPrefix(suffix, "stubbed/proc")
+		return ipc.ReflectInvoker(inspector.NewServerInspector(s)), nil, nil
+	case strings.HasPrefix(suffix, "stubbed/devices"):
+		s.root = "/dev"
+		s.suffix = strings.TrimPrefix(suffix, "stubbed/devices")
+		return ipc.ReflectInvoker(inspector.NewServerInspector(s)), nil, nil
+	case strings.HasPrefix(suffix, "stubless/files"):
+		s.root = cwd
+		s.suffix = strings.TrimPrefix(suffix, "stubless/files")
+		return ipc.ReflectInvoker(&stubwrapper{s}), nil, nil
+	case strings.HasPrefix(suffix, "stubless/proc"):
+		s.root = "/dev"
+		s.suffix = strings.TrimPrefix(suffix, "stubless/proc")
+		return ipc.ReflectInvoker(&stubwrapper{s}), nil, nil
+	case strings.HasPrefix(suffix, "stubless/devices"):
+		s.root = "/proc"
+		s.suffix = strings.TrimPrefix(suffix, "stubless/dev")
 		return ipc.ReflectInvoker(s), nil, nil
+	default:
+		return nil, nil, fmt.Errorf("unrecognised name: %q", suffix)
 	}
 }
 
-func NewFileSvc(stubbed bool) ipc.Dispatcher {
-	return &dispatcher{service: fileSvc, stubbed: stubbed}
-}
-
-func NewProcSvc(stubbed bool) ipc.Dispatcher {
-	return &dispatcher{service: procSvc, stubbed: stubbed}
-}
-
-func NewDeviceSvc(stubbed bool) ipc.Dispatcher {
-	return &dispatcher{service: deviceSvc, stubbed: stubbed}
-}
-
 func readdir(dirname, glob string, ch chan []os.FileInfo, errch chan error) {
 	defer close(ch)
 	defer close(errch)
diff --git a/examples/rockpaperscissors/impl/impl_test.go b/examples/rockpaperscissors/impl/impl_test.go
index af61955..9a2bc32 100644
--- a/examples/rockpaperscissors/impl/impl_test.go
+++ b/examples/rockpaperscissors/impl/impl_test.go
@@ -20,16 +20,16 @@
 		t.Fatalf("NewServer() failed: %v", err)
 	}
 	dispatcher, err := mtlib.NewMountTable("")
-	suffix := "mt"
-	if err := server.Register(suffix, dispatcher); err != nil {
-		t.Fatalf("Register(%v, %v) failed: %v", suffix, dispatcher, err)
-	}
+
 	protocol, hostname := "tcp", "localhost:0"
 	endpoint, err := server.Listen(protocol, hostname)
 	if err != nil {
 		t.Fatalf("Listen(%v, %v) failed: %v", protocol, hostname, err)
 	}
-	address := naming.JoinAddressName(endpoint.String(), suffix)
+	if err := server.Serve("", dispatcher); err != nil {
+		t.Fatalf("Serve(%v) failed: %v", dispatcher, err)
+	}
+	address := naming.JoinAddressName(endpoint.String(), "")
 	vlog.VI(1).Infof("Mount table running at endpoint: %s", address)
 	return address, func() {
 		if err := server.Stop(); err != nil {
@@ -40,22 +40,21 @@
 
 func startRockPaperScissors(t *testing.T, rt veyron2.Runtime, mtAddress string) (*impl.RPS, func()) {
 	ns := rt.Namespace()
-	ns.SetRoots([]string{mtAddress})
+	ns.SetRoots(mtAddress)
 	server, err := rt.NewServer()
 	if err != nil {
 		t.Fatalf("NewServer failed: %v", err)
 	}
 	rpsService := impl.NewRPS()
-	if err := server.Register("", ipc.SoloDispatcher(rps.NewServerRockPaperScissors(rpsService), nil)); err != nil {
-		t.Fatalf("Register failed: %v", err)
-	}
+
 	if _, err = server.Listen("tcp", "localhost:0"); err != nil {
 		t.Fatalf("Listen failed: %v", err)
 	}
+	disp := ipc.SoloDispatcher(rps.NewServerRockPaperScissors(rpsService), nil)
 	names := []string{"rps/judge/test", "rps/player/test", "rps/scorekeeper/test"}
 	for _, n := range names {
-		if err := server.Publish(n); err != nil {
-			t.Fatalf("Publish(%v) failed: %v", n, err)
+		if err := server.Serve(n, disp); err != nil {
+			t.Fatalf("Serve(%v) failed: %v", n, err)
 		}
 	}
 	return rpsService, func() {
diff --git a/examples/rockpaperscissors/rpsbot/main.go b/examples/rockpaperscissors/rpsbot/main.go
index 5b06f08..9e9a011 100644
--- a/examples/rockpaperscissors/rpsbot/main.go
+++ b/examples/rockpaperscissors/rpsbot/main.go
@@ -39,9 +39,8 @@
 	rand.Seed(time.Now().UTC().UnixNano())
 	rpsService := impl.NewRPS()
 
-	if err := server.Register("", ipc.SoloDispatcher(rps.NewServerRockPaperScissors(rpsService), sflag.NewAuthorizerOrDie())); err != nil {
-		vlog.Fatalf("Register failed: %v", err)
-	}
+	dispatcher := ipc.SoloDispatcher(rps.NewServerRockPaperScissors(rpsService), sflag.NewAuthorizerOrDie())
+
 	ep, err := server.Listen(*protocol, *address)
 	if err != nil {
 		vlog.Fatalf("Listen(%q, %q) failed: %v", "tcp", *address, err)
@@ -56,8 +55,8 @@
 		fmt.Sprintf("rps/scorekeeper/%s", hostname),
 	}
 	for _, n := range names {
-		if err := server.Publish(n); err != nil {
-			vlog.Fatalf("Publish(%v) failed: %v", n, err)
+		if err := server.Serve(n, dispatcher); err != nil {
+			vlog.Fatalf("Serve(%v) failed: %v", n, err)
 		}
 	}
 	vlog.Infof("Listening on endpoint /%s (published as %v)", ep, names)
diff --git a/examples/rockpaperscissors/rpsplayercli/main.go b/examples/rockpaperscissors/rpsplayercli/main.go
index 1c8d847..7d0d0d9 100644
--- a/examples/rockpaperscissors/rpsplayercli/main.go
+++ b/examples/rockpaperscissors/rpsplayercli/main.go
@@ -107,9 +107,7 @@
 	}
 	ch := make(chan gameChallenge)
 
-	if err := server.Register("", ipc.SoloDispatcher(rps.NewServerPlayer(&impl{ch: ch}), sflag.NewAuthorizerOrDie())); err != nil {
-		vlog.Fatalf("Register failed: %v", err)
-	}
+	dispatcher := ipc.SoloDispatcher(rps.NewServerPlayer(&impl{ch: ch}), sflag.NewAuthorizerOrDie())
 	ep, err := server.Listen(*protocol, *address)
 	if err != nil {
 		vlog.Fatalf("Listen(%q, %q) failed: %v", "tcp", *address, err)
@@ -118,8 +116,8 @@
 	if err != nil {
 		vlog.Fatalf("os.Hostname failed: %v", err)
 	}
-	if err := server.Publish(fmt.Sprintf("rps/player/%s@%s", os.Getenv("USER"), hostname)); err != nil {
-		vlog.Fatalf("Publish failed: %v", err)
+	if err := server.Serve(fmt.Sprintf("rps/player/%s@%s", os.Getenv("USER"), hostname), dispatcher); err != nil {
+		vlog.Fatalf("Serve failed: %v", err)
 	}
 	vlog.Infof("Listening on endpoint /%s", ep)
 	result := <-ch
diff --git a/examples/rockpaperscissors/rpsscorekeeper/main.go b/examples/rockpaperscissors/rpsscorekeeper/main.go
index 54a7425..aca0293 100644
--- a/examples/rockpaperscissors/rpsscorekeeper/main.go
+++ b/examples/rockpaperscissors/rpsscorekeeper/main.go
@@ -45,9 +45,7 @@
 	ch := make(chan rps.ScoreCard)
 	rpsService := &impl{ch}
 
-	if err := server.Register("", ipc.SoloDispatcher(rps.NewServerScoreKeeper(rpsService), sflag.NewAuthorizerOrDie())); err != nil {
-		vlog.Fatalf("Register failed: %v", err)
-	}
+	dispatcher := ipc.SoloDispatcher(rps.NewServerScoreKeeper(rpsService), sflag.NewAuthorizerOrDie())
 	ep, err := server.Listen(*protocol, *address)
 	if err != nil {
 		vlog.Fatalf("Listen(%q, %q) failed: %v", "tcp", *address, err)
@@ -56,8 +54,8 @@
 	if err != nil {
 		vlog.Fatalf("os.Hostname failed: %v", err)
 	}
-	if err := server.Publish(fmt.Sprintf("rps/scorekeeper/%s", hostname)); err != nil {
-		vlog.Fatalf("Publish failed: %v", err)
+	if err := server.Serve(fmt.Sprintf("rps/scorekeeper/%s", hostname), dispatcher); err != nil {
+		vlog.Fatalf("Serve failed: %v", err)
 	}
 	vlog.Infof("Listening on endpoint /%s", ep)
 
diff --git a/examples/runtime/utils.go b/examples/runtime/utils.go
index 2b4540c..5d35119 100644
--- a/examples/runtime/utils.go
+++ b/examples/runtime/utils.go
@@ -26,12 +26,12 @@
 	if err != nil {
 		vlog.Fatalf("r.NewServer error: %s", err)
 	}
-	if err := server.Register("", new(dispatcher)); err != nil {
-		vlog.Fatalf("server.Register error: %s", err)
-	}
 	if _, err := server.Listen("tcp", "127.0.0.1:0"); err != nil {
 		vlog.Fatalf("server.Listen error: %s", err)
 	}
+	if err := server.Serve("", new(dispatcher)); err != nil {
+		vlog.Fatalf("server.Serve error: %s", err)
+	}
 	return server
 }
 
diff --git a/examples/todos/test/util.go b/examples/todos/test/util.go
index e986be3..e3555c9 100644
--- a/examples/todos/test/util.go
+++ b/examples/todos/test/util.go
@@ -55,16 +55,15 @@
 
 	// Register the services.
 	storeDisp := server.NewStoreDispatcher(storeService, nil)
-	if err := s.Register("", storeDisp); err != nil {
-		log.Fatal("s.Register(storeDisp) failed: ", err)
-	}
 
 	// Create an endpoint and start listening.
 	ep, err := s.Listen("tcp", "127.0.0.1:0")
 	if err != nil {
 		log.Fatal("s.Listen() failed: ", err)
 	}
-
+	if err := s.Serve("", storeDisp); err != nil {
+		log.Fatal("s.Serve(storeDisp) failed: ", err)
+	}
 	return naming.JoinAddressName(ep.String(), "//"), func() {
 		s.Stop()
 		os.Remove(dbDir)
diff --git a/examples/tunnel/tunneld/main.go b/examples/tunnel/tunneld/main.go
index 33291a7..4520127 100644
--- a/examples/tunnel/tunneld/main.go
+++ b/examples/tunnel/tunneld/main.go
@@ -48,9 +48,6 @@
 	}
 	defer server.Stop()
 
-	if err := server.Register("", ipc.SoloDispatcher(tunnel.NewServerTunnel(&impl.T{}), sflag.NewAuthorizerOrDie())); err != nil {
-		vlog.Fatalf("Register failed: %v", err)
-	}
 	ep, err := server.Listen(*protocol, *address)
 	if err != nil {
 		vlog.Fatalf("Listen(%q, %q) failed: %v", "tcp", *address, err)
@@ -73,8 +70,8 @@
 	}
 	published := false
 	for _, n := range names {
-		if err := server.Publish(n); err != nil {
-			vlog.Infof("Publish(%v) failed: %v", n, err)
+		if err := server.Serve(n, ipc.SoloDispatcher(tunnel.NewServerTunnel(&impl.T{}), sflag.NewAuthorizerOrDie())); err != nil {
+			vlog.Infof("Serve(%v) failed: %v", n, err)
 			continue
 		}
 		published = true
diff --git a/examples/unresolve/test_util.go b/examples/unresolve/test_util.go
index 6a470ed..7725c67 100644
--- a/examples/unresolve/test_util.go
+++ b/examples/unresolve/test_util.go
@@ -9,6 +9,7 @@
 	"veyron2/ipc"
 	"veyron2/naming"
 	"veyron2/rt"
+	"veyron2/security"
 	mtidl "veyron2/services/mounttable"
 	"veyron2/vlog"
 
@@ -23,50 +24,39 @@
 	return rt.Init(opts...).Shutdown
 }
 
-func newServer(opts ...ipc.ServerOpt) ipc.Server {
+func createServer(name string, dispatcher ipc.Dispatcher, opts ...ipc.ServerOpt) (ipc.Server, string) {
 	server, err := rt.R().NewServer(opts...)
 	if err != nil {
 		panic(fmt.Sprintf("r.NewServer failed with %v", err))
 	}
-	return server
-}
-
-func createServer(server ipc.Server, prefix string, dispatcher ipc.Dispatcher) string {
-	if err := server.Register(prefix, dispatcher); err != nil {
-		panic(fmt.Sprintf("server.Register failed with %v", err))
-	}
 	ep, err := server.Listen("tcp", "127.0.0.1:0")
 	if err != nil {
 		panic(fmt.Sprintf("server.Listen failed with %v", err))
 	}
-	return naming.JoinAddressName(ep.String(), prefix)
+	if err := server.Serve(name, dispatcher); err != nil {
+		panic(fmt.Sprintf("server.Serve failed with %v", err))
+	}
+	oa := naming.JoinAddressName(ep.String(), "")
+	vlog.Infof("created %s -> %s", name, oa)
+	return server, oa
 }
 
-func serverMain(servesMT bool, serviceCreator func(ipc.Server) string, args []string) {
+func childMT(args []string) {
 	defer initRT()()
-	server := newServer(veyron2.ServesMountTableOpt(servesMT))
-	defer server.Stop()
-	service := serviceCreator(server)
-	vlog.Infof("created %v", service)
 	for _, arg := range args {
-		if err := server.Publish(arg); err != nil {
-			panic(fmt.Sprintf("server.Publish(%q) failed with %v", arg, err))
-		}
+		server, _ := createMTServer(arg)
+		defer server.Stop()
 	}
 	fmt.Println("ready")
 	blackbox.WaitForEOFOnStdin()
 }
 
-func createMT(server ipc.Server) string {
+func createMTServer(mp string) (ipc.Server, string) {
 	mt, err := mounttable.NewMountTable("")
 	if err != nil {
 		panic(fmt.Sprintf("NewMountTable failed with %v", err))
 	}
-	return createServer(server, "mt", mt)
-}
-
-func childMT(args []string) {
-	serverMain(true, createMT, args)
+	return createServer(mp, mt, veyron2.ServesMountTableOpt(true))
 }
 
 func createMTClient(name string) mtidl.MountTable {
@@ -89,12 +79,15 @@
 	return nil
 }
 
-func createFortune(server ipc.Server) string {
-	return createServer(server, "fortune", ipc.SoloDispatcher(fortuneidl.NewServerFortune(new(fortune)), nil))
-}
-
 func childFortune(args []string) {
-	serverMain(false, createFortune, args)
+	defer initRT()()
+	server, _ := createServer(args[0], ipc.SoloDispatcher(fortuneidl.NewServerFortune(new(fortune)), nil))
+	defer server.Stop()
+	for _, arg := range args[1:] {
+		server.Serve(arg, nil)
+	}
+	fmt.Println("ready")
+	blackbox.WaitForEOFOnStdin()
 }
 
 type fortuneCustomUnresolve struct {
@@ -122,18 +115,40 @@
 	return reply, nil
 }
 
-func createFortuneCustomUnresolve(server ipc.Server) string {
-	oa := createServer(server, "tell/me/the/future", ipc.SoloDispatcher(fortuneidl.NewServerFortune(new(fortuneCustomUnresolve)), nil))
-	ep, _ := naming.SplitAddressName(oa)
-	oa = naming.MakeTerminal(naming.JoinAddressName(ep, "tell/me"))
-	// Doesn't get unmounted.  Fine for a test.
-	oa = naming.MakeTerminal(oa)
-	rt.R().Namespace().Mount(rt.R().NewContext(), "I/want/to/know", oa, 0)
-	return oa
+// Can't use the soloDispatcher (which is a bad name in any case) since it
+// doesn't allow name suffixes (which is also a silly restriction).
+// TODO(cnicolaou): rework soloDispatcher.
+type fortuned struct{ obj interface{} }
+
+func (f *fortuned) Lookup(string) (ipc.Invoker, security.Authorizer, error) {
+	return ipc.ReflectInvoker(f.obj), nil, nil
+}
+
+func createFortuneCustomUnresolve(mp string) (ipc.Server, string) {
+	server, oa := createServer(mp, &fortuned{fortuneidl.NewServerFortune(new(fortuneCustomUnresolve))})
+	rt.R().Namespace().Mount(rt.R().NewContext(), "I/want/to/know", oa+"//", 0)
+	rt.R().Namespace().Mount(rt.R().NewContext(), "tell/me", oa+"//", 0)
+	return server, oa
 }
 
 func childFortuneCustomUnresolve(args []string) {
-	serverMain(false, createFortuneCustomUnresolve, args)
+	defer initRT()()
+	for _, arg := range args {
+		server, _ := createFortuneCustomUnresolve(arg)
+		defer server.Stop()
+	}
+	fmt.Println("ready")
+	blackbox.WaitForEOFOnStdin()
+}
+
+func childFortuneNoIDL(args []string) {
+	defer initRT()()
+	for _, arg := range args {
+		server, _ := createServer(arg, ipc.SoloDispatcher(new(fortuneNoIDL), nil))
+		defer server.Stop()
+	}
+	fmt.Println("ready")
+	blackbox.WaitForEOFOnStdin()
 }
 
 func createFortuneClient(rt veyron2.Runtime, name string) fortuneidl.Fortune {
@@ -163,14 +178,6 @@
 	return reply, nil
 }
 
-func createFortuneNoIDL(server ipc.Server) string {
-	return createServer(server, "fortune", ipc.SoloDispatcher(new(fortuneNoIDL), nil))
-}
-
-func childFortuneNoIDL(args []string) {
-	serverMain(false, createFortuneNoIDL, args)
-}
-
 func resolveStep(t *testing.T, name string) string {
 	client := createMTClient(name)
 	results, suffix, err := client.ResolveStep(rt.R().NewContext())
@@ -227,3 +234,16 @@
 	}
 	return results[0]
 }
+
+func glob(t *testing.T, pattern string) []string {
+	var replies []string
+	rc, err := rt.R().Namespace().Glob(rt.R().NewContext(), pattern)
+	if err != nil {
+		t.Errorf("Glob(%s): err %v", pattern, err)
+		return nil
+	}
+	for s := range rc {
+		replies = append(replies, s.Name)
+	}
+	return replies
+}
diff --git a/examples/unresolve/unresolve_test.go b/examples/unresolve/unresolve_test.go
index edf2e7e..16826b0 100644
--- a/examples/unresolve/unresolve_test.go
+++ b/examples/unresolve/unresolve_test.go
@@ -27,50 +27,43 @@
 //        |"b"
 //        |
 //       (B)
-//         \_____________________________________________
-//          |    |    |                  |     |     |   \
-//          |"c" |"d" | "I/want/to/know" |"e1" |"e2" |"f" |"g"
+//         \_______________________________________________
 //          |    |    |                  |     |     |    |
-//         (C)  (D)  (D/tell/me")       (E)   (E)   (F)  (G)
+//          |"c" |"d" | "I/want/to/know" |"e1" |"e2" |"f" |"g"
+//          |    |    | "tell/me"        |     |     |    |
+//         (C)  (D)  (D)                (E)   (E)    (F) (G)
 //
-// A mounttable service (A) with OA "aEP/mt" acting as a root mounttable.
+// A mounttable service (A) with OA "aEP" acting as a root mounttable.
 //
-// A mounttable service (B) with OA "bEP/mt", mounting its ep "bEP" as "b" under
+// A mounttable service (B) with OA "bEP", mounting its ep "bEP" as "b" under
 // mounttable A.
 //
-// A fortune service (C) with OA "eEP/fortune", mouting its ep "eEP" as "c"
+// A fortune service (C) with OA "cEP", mounting its ep "cEP" as "c"
 // under mounttable B.  [ This is the vanilla case. ]
 //
-// A fortune service (D) with OA "dEP/tell/me/the/future", mounting its ep "dEP"
+// A fortune service (D) with OA "dEP", mounting its ep "dEP"
 // automatically as "d" under mounttable B, and also mounting the OA
-// "dEP/tell/me" manually as "I/want/to/know" under mounttable B.  It implements
-// its own custom UnresolveStep.  [ This demonstrates using a custom
-// UnresolveStep implementation with an IDL-based service. ]
+// "dEP" manually as "I/want/to/know" and "tell/me under mounttable B.
+// It implements its own custom UnresolveStep.
+// [ This demonstrates using a custom UnresolveStep implementation with
+// an IDL-based service. ]
 //
-// A fortune service (E) with OA "eEP/fortune", mounting its ep "eEP" as "e1"
+// A fortune service (E) with OA "eEP", mounting its ep "eEP" as "e1"
 // and as "e2" under mounttable B.  [ This shows a service published under more
 // than one name. ]
 //
-// A fortune service (F) with OA "fEP/fortune", with mounttable root "aOA/b/mt"
-// mounting its ep "fEP" as "f" under "aOA/b/mt" (essentially, under mounttable
+// A fortune service (F) with OA "fEP", with mounttable root "aOA/b/"
+// mounting its ep "fEP" as "f" under "aOA/b" (essentially, under mounttable
 // B).  [ This shows a service whose local root is a name that resolves to a
 // mounttable via another mounttable (so local root is not just an OA ].
+// TODO(cnicolaou): move this case (multihop namespace root to the namespace
+// tests)
 //
-// A fortune service (G) with OA "gEP/fortune" that is not based on an IDL.  G
+// A fortune service (G) with OA "gEP" that is not based on an IDL.  G
 // mounts itself as "g" under mounttable B, and defines its own UnresolveStep.
 // [ This demonstrates defining UnresolveStep for a service that is not
 // IDL-based. ]
 //
-// The MountTables used here are configured to use an internal prefix (mt)
-// for dispatching RPCs. This means that the client code has to manipulate
-// the names to ensure that resolution is terminated in the appropriate
-// places in the name since the MountTable expects to be invoked as
-// /<address>/mt.METHODS rather than just /<address>.METHODS.
-// In addition, since this test invokes methods directly on the MountTable
-// it needs to use a terminal name to force resolution to stop at the MountTable
-// itself, rather than using the MountTable to resolve the name. In practice,
-// this means that names of the form /<endpoint>//mt/... must be used to
-// invoke methods on the MountTable served on <endpoint>/mt.
 
 func TestHelperProcess(t *testing.T) {
 	blackbox.HelperProcess(t)
@@ -99,15 +92,16 @@
 	// TODO(ataly): Eventually we want to use the same identities the servers
 	// would have if they were running in production.
 	defer initRT()()
-	mtServer := newServer(veyron2.ServesMountTableOpt(true))
-	defer mtServer.Stop()
 
 	// Create mounttable A.
-	aOA := createMT(mtServer)
+	mtServer, aOA := createMTServer("")
 	if len(aOA) == 0 {
 		t.Fatalf("aOA is empty")
 	}
-	// A's object addess, aOA, is /<address>/mt
+	defer mtServer.Stop()
+	rt.R().Namespace().SetRoots(aOA)
+
+	// A's object addess, aOA, is /<address>
 	vlog.Infof("aOA=%v", aOA)
 
 	idA := rt.R().Identity()
@@ -115,7 +109,7 @@
 
 	// Create mounttable B.
 	// Mounttable B uses A as a root, that is, Publish calls made for
-	// services running in B will appear in A, as mt/<suffix used in publish>
+	// services running in B will appear in A, as <suffix used in publish>
 	b := blackbox.HelperCommand(t, "childMT", "b")
 	defer shutdown(b)
 
@@ -125,17 +119,15 @@
 	b.Cmd.Start()
 	b.Expect("ready")
 
-	// We want to obtain the name for the MountTable mounted in A as mt/b,
+	// We want to obtain the name for the MountTable mounted in A as b,
 	// in particular, we want the OA of B's Mounttable service.
-	// We do so by asking Mounttable A to resolve //mt/b using its
-	// ResolveStep method. The name (//mt/b) has to be terminal since we are
+	// We do so by asking Mounttable A to resolve //b using its
+	// ResolveStep method. The name (//b) has to be terminal since we are
 	// invoking a methond on the MountTable rather asking the MountTable to
 	// resolve the name!
-	aAddr, _ := naming.SplitAddressName(aOA)
-	aName := naming.JoinAddressName(aAddr, "//mt/b")
-	bName := resolveStep(t, aName)
+	aName := naming.Join(aOA, "//b")
 
-	bOA := naming.Join(bName, "mt")
+	bOA := resolveStep(t, aName)
 	vlog.Infof("bOA=%v", bOA)
 	bAddr, _ := naming.SplitAddressName(bOA)
 
@@ -147,10 +139,10 @@
 	c.Cmd.Env = append(c.Cmd.Env, fmt.Sprintf("VEYRON_IDENTITY=%v", idFile), fmt.Sprintf("NAMESPACE_ROOT=%v", bOA))
 	c.Cmd.Start()
 	c.Expect("ready")
-	cEP := resolveStep(t, naming.JoinAddressName(bAddr, "//mt/c"))
+	cEP := resolveStep(t, naming.Join(bOA, "//c"))
 	vlog.Infof("cEP=%v", cEP)
 
-	// Create server D.
+	// Create server D and the fortune service with a custom unresolver
 	d := blackbox.HelperCommand(t, "childFortuneCustomUnresolve", "d")
 	defer shutdown(d)
 	idFile = security.SaveIdentityToFile(security.NewBlessedIdentity(idA, "test"))
@@ -158,7 +150,7 @@
 	d.Cmd.Env = append(d.Cmd.Env, fmt.Sprintf("VEYRON_IDENTITY=%v", idFile), fmt.Sprintf("NAMESPACE_ROOT=%v", bOA))
 	d.Cmd.Start()
 	d.Expect("ready")
-	dEP := resolveStep(t, naming.JoinAddressName(bAddr, "//mt/d"))
+	dEP := resolveStep(t, naming.Join(bOA, "//d"))
 	vlog.Infof("dEP=%v", dEP)
 
 	// Create server E.
@@ -169,18 +161,17 @@
 	e.Cmd.Env = append(e.Cmd.Env, fmt.Sprintf("VEYRON_IDENTITY=%v", idFile), fmt.Sprintf("NAMESPACE_ROOT=%v", bOA))
 	e.Cmd.Start()
 	e.Expect("ready")
-	eEP := resolveStep(t, naming.JoinAddressName(bAddr, "//mt/e1"))
+	eEP := resolveStep(t, naming.Join(bOA, "//e1"))
 	vlog.Infof("eEP=%v", eEP)
 
-	// Create server F.
 	f := blackbox.HelperCommand(t, "childFortune", "f")
 	defer shutdown(f)
 	idFile = security.SaveIdentityToFile(security.NewBlessedIdentity(idA, "test"))
 	defer os.Remove(idFile)
-	f.Cmd.Env = append(f.Cmd.Env, fmt.Sprintf("VEYRON_IDENTITY=%v", idFile), fmt.Sprintf("NAMESPACE_ROOT=%v", naming.Join(aOA, "b/mt")))
+	f.Cmd.Env = append(f.Cmd.Env, fmt.Sprintf("VEYRON_IDENTITY=%v", idFile), fmt.Sprintf("NAMESPACE_ROOT=%v", naming.Join(aOA, "b")))
 	f.Cmd.Start()
 	f.Expect("ready")
-	fEP := resolveStep(t, naming.JoinAddressName(bAddr, "//mt/f"))
+	fEP := resolveStep(t, naming.JoinAddressName(bAddr, "//f"))
 	vlog.Infof("fEP=%v", fEP)
 
 	// Create server G.
@@ -191,9 +182,11 @@
 	g.Cmd.Env = append(g.Cmd.Env, fmt.Sprintf("VEYRON_IDENTITY=%v", idFile), fmt.Sprintf("NAMESPACE_ROOT=%v", bOA))
 	g.Cmd.Start()
 	g.Expect("ready")
-	gEP := resolveStep(t, naming.JoinAddressName(bAddr, "//mt/g"))
+	gEP := resolveStep(t, naming.Join(bOA, "//g"))
 	vlog.Infof("gEP=%v", gEP)
 
+	vlog.Infof("ls /... %v", glob(t, "..."))
+
 	// Check that things resolve correctly.
 
 	// Create a client runtime with oOA as its root.
@@ -207,13 +200,13 @@
 	resolveCases := []struct {
 		name, resolved string
 	}{
-		{"b/mt/c", cEP},
-		{"b/mt/d", dEP},
-		{"b/mt/I/want/to/know", naming.MakeTerminal(naming.Join(dEP, "tell/me"))},
-		{"b/mt/e1", eEP},
-		{"b/mt/e2", eEP},
-		{"b/mt/f", fEP},
-		{"b/mt/g", gEP},
+		{"b/c", cEP},
+		{"b/d", dEP},
+		{"b/I/want/to/know", dEP},
+		{"b/tell/me/the/future", naming.Join(dEP, "the/future")},
+		{"b/e1", eEP},
+		{"b/e2", eEP},
+		{"b/g", gEP},
 	}
 	for _, c := range resolveCases {
 		if want, got := c.resolved, resolve(t, r.Namespace(), c.name); want != got {
@@ -223,36 +216,35 @@
 
 	// Verify that we can talk to the servers we created, and that unresolve
 	// one step at a time works.
-
 	unresolveStepCases := []struct {
 		name, unresStep1, unresStep2 string
 	}{
 		{
-			"b/mt/c/fortune",
-			naming.Join(bOA, "c/fortune"),
-			naming.Join(aOA, "b/mt/c/fortune"),
+			"b/c",
+			naming.Join(bOA, "c"),
+			naming.Join(aOA, "b/c"),
 		},
 		{
-			"b/mt/d/tell/me/the/future",
+			"b/tell/me",
 			naming.Join(bOA, "I/want/to/know/the/future"),
-			naming.Join(aOA, "b/mt/I/want/to/know/the/future"),
+			naming.Join(aOA, "b/I/want/to/know/the/future"),
 		},
 		{
-			"b/mt/f/fortune",
-			naming.Join(bOA, "f/fortune"),
-			naming.Join(aOA, "b/mt/f/fortune"),
+			"b/f",
+			naming.Join(bOA, "f"),
+			naming.Join(aOA, "b/f"),
 		},
 		{
-			"b/mt/g/fortune",
+			"b/g",
 			naming.Join(bOA, "g/fortune"),
-			naming.Join(aOA, "b/mt/g/fortune"),
+			naming.Join(aOA, "b/g/fortune"),
 		},
 	}
 	for _, c := range unresolveStepCases {
 		// Verify that we can talk to the server.
 		client := createFortuneClient(r, c.name)
 		if fortuneMessage, err := client.Get(r.NewContext()); err != nil {
-			t.Errorf("fortune.Get failed with %v", err)
+			t.Errorf("fortune.Get: %s failed with %v", c.name, err)
 		} else if fortuneMessage != fixedFortuneMessage {
 			t.Errorf("fortune expected %q, got %q instead", fixedFortuneMessage, fortuneMessage)
 		}
@@ -272,7 +264,7 @@
 	// instead of one.
 
 	// Verify that we can talk to server E.
-	eClient := createFortuneClient(r, "b/mt/e1/fortune")
+	eClient := createFortuneClient(r, "b/e1")
 	if fortuneMessage, err := eClient.Get(ctx); err != nil {
 		t.Errorf("fortune.Get failed with %v", err)
 	} else if fortuneMessage != fixedFortuneMessage {
@@ -284,18 +276,18 @@
 	if err != nil {
 		t.Errorf("UnresolveStep failed with %v", err)
 	}
-	if want, got := []string{naming.Join(bOA, "e1/fortune"), naming.Join(bOA, "e2/fortune")}, eUnres; !reflect.DeepEqual(want, got) {
+	if want, got := []string{naming.Join(bOA, "e1"), naming.Join(bOA, "e2")}, eUnres; !reflect.DeepEqual(want, got) {
 		t.Errorf("e.UnresolveStep expected %q, got %q instead", want, got)
 	}
 
 	// Try unresolve step on a random name in B.
-	if want, got := naming.JoinAddressName(aAddr, "mt/b/mt/some/random/name"),
-		unresolveStep(t, ctx, createMTClient(naming.JoinAddressName(bAddr, "//mt/some/random/name"))); want != got {
+	if want, got := naming.Join(aOA, "b/some/random/name"),
+		unresolveStep(t, ctx, createMTClient(naming.Join(bOA, "//some/random/name"))); want != got {
 		t.Errorf("b.UnresolveStep expected %q, got %q instead", want, got)
 	}
 
 	// Try unresolve step on a random name in A.
-	if unres, err := createMTClient(naming.JoinAddressName(aAddr, "//mt/another/random/name")).UnresolveStep(ctx); err != nil {
+	if unres, err := createMTClient(naming.Join(aOA, "//another/random/name")).UnresolveStep(ctx); err != nil {
 		t.Errorf("UnresolveStep failed with %v", err)
 	} else if len(unres) > 0 {
 		t.Errorf("b.UnresolveStep expected no results, got %q instead", unres)
@@ -305,24 +297,26 @@
 	unresolveCases := []struct {
 		name, want string
 	}{
-		{"b/mt/c/fortune", naming.Join(aOA, "b/mt/c/fortune")},
-		{naming.Join(bOA, "c/fortune"), naming.Join(aOA, "b/mt/c/fortune")},
-		{naming.Join(cEP, "fortune"), naming.Join(aOA, "b/mt/c/fortune")},
+		{"b/c", naming.Join(aOA, "b/c")},
+		{naming.Join(bOA, "c"), naming.Join(aOA, "b/c")},
+		{naming.Join(cEP, ""), naming.Join(aOA, "b/c")},
 
-		{"b/mt/d/tell/me/the/future", naming.Join(aOA, "b/mt/I/want/to/know/the/future")},
-		{naming.Join(bOA, "d/tell/me/the/future"), naming.Join(aOA, "b/mt/I/want/to/know/the/future")},
-		{"b/mt/I/want/to/know/the/future", naming.Join(aOA, "b/mt/I/want/to/know/the/future")},
-		{naming.Join(bOA, "I/want/to/know/the/future"), naming.Join(aOA, "b/mt/I/want/to/know/the/future")},
-		{naming.Join(dEP, "tell/me/the/future"), naming.Join(aOA, "b/mt/I/want/to/know/the/future")},
+		{"b/tell/me/the/future", naming.Join(aOA, "b/I/want/to/know/the/future")},
+		{"b/I/want/to/know/the/future", naming.Join(aOA, "b/I/want/to/know/the/future")},
+		{naming.Join(bOA, "d/tell/me/the/future"), naming.Join(aOA, "b/I/want/to/know/the/future")},
 
-		{"b/mt/e1/fortune", naming.Join(aOA, "b/mt/e1/fortune")},
-		{"b/mt/e2/fortune", naming.Join(aOA, "b/mt/e1/fortune")},
+		{naming.Join(bOA, "I/want/to/know/the/future"), naming.Join(aOA, "b/I/want/to/know/the/future")},
+		{naming.Join(dEP, "tell/me/the/future"), naming.Join(aOA, "b/I/want/to/know/the/future")},
 
-		{"b/mt/f/fortune", naming.Join(aOA, "b/mt/f/fortune")},
-		{naming.Join(fEP, "fortune"), naming.Join(aOA, "b/mt/f/fortune")},
-		{"b/mt/g/fortune", naming.Join(aOA, "b/mt/g/fortune")},
-		{naming.Join(bOA, "g/fortune"), naming.Join(aOA, "b/mt/g/fortune")},
-		{naming.Join(gEP, "fortune"), naming.Join(aOA, "b/mt/g/fortune")},
+		{"b/e1", naming.Join(aOA, "b/e1")},
+		{"b/e2", naming.Join(aOA, "b/e1")},
+
+		{"b/f", naming.Join(aOA, "b/f")},
+		{naming.Join(fEP, ""), naming.Join(aOA, "b/f")},
+
+		{"b/g", naming.Join(aOA, "b/g/fortune")},
+		{naming.Join(bOA, "g"), naming.Join(aOA, "b/g/fortune")},
+		{naming.Join(gEP, ""), naming.Join(aOA, "b/g/fortune")},
 	}
 	for _, c := range unresolveCases {
 		if want, got := c.want, unresolve(t, r.Namespace(), c.name); want != got {
diff --git a/examples/wspr_sample/sampled/lib/sampled.go b/examples/wspr_sample/sampled/lib/sampled.go
index f00b387..530b838 100644
--- a/examples/wspr_sample/sampled/lib/sampled.go
+++ b/examples/wspr_sample/sampled/lib/sampled.go
@@ -2,6 +2,7 @@
 
 import (
 	"fmt"
+	"strings"
 
 	"veyron2"
 	"veyron2/ipc"
@@ -12,11 +13,15 @@
 )
 
 type cacheDispatcher struct {
-	cached interface{}
+	cache        interface{}
+	errorThrower interface{}
 }
 
-func (cd *cacheDispatcher) Lookup(string) (ipc.Invoker, security.Authorizer, error) {
-	return ipc.ReflectInvoker(cd.cached), nil, nil
+func (cd *cacheDispatcher) Lookup(suffix string) (ipc.Invoker, security.Authorizer, error) {
+	if strings.HasPrefix(suffix, "errorThrower") {
+		return ipc.ReflectInvoker(cd.errorThrower), nil, nil
+	}
+	return ipc.ReflectInvoker(cd.cache), nil, nil
 }
 
 func StartServer(r veyron2.Runtime) (ipc.Server, naming.Endpoint, error) {
@@ -26,16 +31,9 @@
 		return nil, nil, fmt.Errorf("failure creating server: %v", err)
 	}
 
-	// Register the "cache" prefix with the cache dispatcher.
-	serverCache := sample.NewServerCache(NewCached())
-	if err := s.Register("cache", &cacheDispatcher{cached: serverCache}); err != nil {
-		return nil, nil, fmt.Errorf("error registering cache service: %v", err)
-	}
-
-	// Register the "errorthrower" prefix with the errorthrower dispatcher.
-	errorThrower := sample.NewServerErrorThrower(NewErrorThrower())
-	if err := s.Register("errorthrower", &cacheDispatcher{cached: errorThrower}); err != nil {
-		return nil, nil, fmt.Errorf("error registering error thrower service: %v", err)
+	disp := &cacheDispatcher{
+		cache:        sample.NewServerCache(NewCached()),
+		errorThrower: sample.NewServerErrorThrower(NewErrorThrower()),
 	}
 
 	// Create an endpoint and begin listening.
@@ -46,9 +44,8 @@
 
 	// Publish the cache service. This will register it in the mount table and maintain the
 	// registration until StopServing is called.
-	if err := s.Publish("cache"); err != nil {
+	if err := s.Serve("cache", disp); err != nil {
 		return nil, nil, fmt.Errorf("error publishing service: %v", err)
 	}
-
 	return s, endpoint, nil
 }
diff --git a/lib/signals/signals_test.go b/lib/signals/signals_test.go
index 08d54ea..bbd576c 100644
--- a/lib/signals/signals_test.go
+++ b/lib/signals/signals_test.go
@@ -287,16 +287,15 @@
 	if err != nil {
 		t.Fatalf("Got error: %v", err)
 	}
-	const suffix = ""
 	ch := make(chan string)
-	if err := server.Register(suffix, ipc.SoloDispatcher(node.NewServerConfig(&configServer{ch}), vflag.NewAuthorizerOrDie())); err != nil {
-		t.Fatalf("Got error: %v", err)
-	}
 	var ep naming.Endpoint
 	if ep, err = server.Listen("tcp", "127.0.0.1:0"); err != nil {
 		t.Fatalf("Got error: %v", err)
 	}
-	return server, naming.JoinAddressName(ep.String(), suffix), ch
+	if err := server.Serve("", ipc.SoloDispatcher(node.NewServerConfig(&configServer{ch}), vflag.NewAuthorizerOrDie())); err != nil {
+		t.Fatalf("Got error: %v", err)
+	}
+	return server, naming.JoinAddressName(ep.String(), ""), ch
 
 }
 
diff --git a/lib/testutil/modules/ls.go b/lib/testutil/modules/ls.go
index 936d50a..214856f 100644
--- a/lib/testutil/modules/ls.go
+++ b/lib/testutil/modules/ls.go
@@ -99,7 +99,7 @@
 	if err != nil {
 		return []string{}, err
 	}
-	stream, err := mtpt.Glob(nil, pattern)
+	stream, err := mtpt.Glob(rt.R().NewContext(), pattern)
 	if err != nil {
 		return []string{}, err
 	}
diff --git a/lib/testutil/modules/mounttable.go b/lib/testutil/modules/mounttable.go
index 2516c65..13559ce 100644
--- a/lib/testutil/modules/mounttable.go
+++ b/lib/testutil/modules/mounttable.go
@@ -11,7 +11,6 @@
 	mounttable "veyron/services/mounttable/lib"
 
 	"veyron2"
-	"veyron2/ipc"
 	"veyron2/naming"
 	"veyron2/rt"
 	"veyron2/vlog"
@@ -44,16 +43,15 @@
 
 func (mt *mountTable) Help() string {
 	if mt.root {
-		return `<prefix>
-run a root mounTable using Register(prefix...)`
+		return "run a root mounTable"
 	} else {
-		return `<root> <prefix> <suffix>
-run a mountTable with root as its root mountTable and using Register(prefix...) and Publish(suffix)`
+		return `<root> <mount point>
+run a mountTable, with <root> as the root for its Namespace, mounted on <mount point>`
 	}
 }
 
 func (mt *mountTable) Run(args []string) (Variables, []string, Handle, error) {
-	if (mt.root && len(args) != 1) || (!mt.root && len(args) != 3) {
+	if (mt.root && len(args) != 0) || (!mt.root && len(args) != 2) {
 		return nil, nil, nil, fmt.Errorf("wrong #args: %s", mt.Help())
 	}
 	name := map[bool]string{true: "rootMT", false: "nodeMT"}[mt.root]
@@ -73,14 +71,14 @@
 }
 
 func rootMTChild(args []string) {
-	if len(args) != 1 {
+	if len(args) != 0 {
 		bbExitWithError("wrong #args")
 	}
 	serveMountTable(true, args)
 }
 
 func leafMTChild(args []string) {
-	if len(args) != 2 {
+	if len(args) != 1 {
 		bbExitWithError("wrong #args")
 	}
 	serveMountTable(false, args)
@@ -93,18 +91,25 @@
 	if err != nil {
 		bbExitWithError(fmt.Sprintf("root failed: %v", err))
 	}
-	prefix := args[0]
-	name, err := newMountTableServer(server, prefix)
+	mp := ""
+	if !root {
+		mp = args[0]
+	}
+	mt, err := mounttable.NewMountTable("")
 	if err != nil {
+		bbExitWithError(fmt.Sprintf("mounttable.NewMountTable failed with %v", err))
+	}
+	ep, err := server.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		bbExitWithError(fmt.Sprintf("server.Listen failed with %v", err))
+	}
+	if err := server.Serve(mp, mt); err != nil {
 		bbExitWithError(fmt.Sprintf("root failed: %v", err))
 	}
-	addr, _ := naming.SplitAddressName(name)
-	if !root {
-		if err := server.Publish(args[1]); err != nil {
-			bbExitWithError(fmt.Sprintf("root failed: %v", err))
-		}
-	}
-	fmt.Printf("MT_ADDR=%s\n", addr)
+	name := naming.JoinAddressName(ep.String(), "")
+	vlog.Infof("Serving MountTable on %q", name)
+
+	fmt.Printf("MT_ADDR=%s\n", ep)
 	fmt.Printf("MT_NAME=%s\n", name)
 	fmt.Printf("PID=%d\n", os.Getpid())
 	fmt.Println("running\n")
@@ -112,23 +117,6 @@
 	fmt.Println("done\n")
 }
 
-func newMountTableServer(server ipc.Server, prefix string) (string, error) {
-	mt, err := mounttable.NewMountTable("")
-	if err != nil {
-		return "", fmt.Errorf("NewMountTableServer failed with %v", err)
-	}
-	if err := server.Register(prefix, mt); err != nil {
-		return "", fmt.Errorf("server.Register failed with %v", err)
-	}
-	ep, err := server.Listen("tcp", "127.0.0.1:0")
-	if err != nil {
-		return "", fmt.Errorf("server.Listen failed with %v", err)
-	}
-	name := naming.JoinAddressName(ep.String(), prefix)
-	vlog.Infof("Serving MountTable on %q", name)
-	return name, nil
-}
-
 type setroot struct{}
 
 func NewSetRoot() T {
@@ -151,7 +139,7 @@
 			return nil, nil, nil, fmt.Errorf("name %q must be rooted", r)
 		}
 	}
-	rt.R().Namespace().SetRoots(args)
+	rt.R().Namespace().SetRoots(args...)
 	return nil, nil, nil, nil
 }
 
diff --git a/lib/testutil/modules/servers.go b/lib/testutil/modules/servers.go
index bfb2c43..1502dae 100644
--- a/lib/testutil/modules/servers.go
+++ b/lib/testutil/modules/servers.go
@@ -29,39 +29,22 @@
 
 func serve(msg string, dispatcher ipc.Dispatcher, args []string) {
 	rt.Init()
-	if len(args) != 3 {
+	if len(args) != 1 {
 		bbExitWithError("wrong #args")
 	}
-	root := args[0]
-	prefix := args[1]
-	mp := args[2]
-	publish := true
-	if len(root) == 0 {
-		publish = false
-	}
+	mp := args[0]
 	fmt.Println("ready")
 	server, err := rt.R().NewServer()
 	if err != nil {
 		bbExitWithError(fmt.Sprintf("%s failed: %v", msg, err))
 	}
-	if err := server.Register(prefix, dispatcher); err != nil {
-		bbExitWithError(fmt.Sprintf("%s failed: %v", msg, err))
-	}
 	ep, err := server.Listen("tcp", "127.0.0.1:0")
 	if err != nil {
 		bbExitWithError(fmt.Sprintf("%s failed: %v", msg, err))
 	}
-	// Sadly, the name a client needs to use to invoke RPCs on us
-	// depends on whether we are using a MountTable or not. If we're
-	// not using a MountTable then the name is /<ep>/<prefix>, but if we
-	// are then it's /<ep of mount table>/<mp>!!
-	if publish {
-		fmt.Printf("NAME=%s\n", naming.MakeTerminal(naming.JoinAddressName(ep.String(), mp)))
-		if err := server.Publish(mp); err != nil {
-			bbExitWithError(fmt.Sprintf("%s failed: %v", msg, err))
-		}
-	} else {
-		fmt.Printf("NAME=%s\n", naming.MakeTerminal(naming.JoinAddressName(ep.String(), prefix)))
+	fmt.Printf("NAME=%s\n", naming.MakeTerminal(naming.JoinAddressName(ep.String(), "")))
+	if err := server.Serve(mp, dispatcher); err != nil {
+		bbExitWithError(fmt.Sprintf("%s failed: %v", msg, err))
 	}
 	fmt.Printf("ADDR=%s\n", ep)
 	fmt.Printf("PID=%d\n", os.Getpid())
@@ -96,15 +79,15 @@
 		return `<name> <message>
 executes name.Time(message)`
 	}
-	return `<root> <prefix> <suffix>
-runs a clock server with root as its root mountTable, Register(prefix...) and  Pubish(suffix)`
+	return `<root> <mountpoint>
+runs a clock server with root as its root mount table, mounted at <mountpoint>`
 }
 
 func (c *clock) Daemon() bool { return !c.client }
 
 func (c *clock) Run(args []string) (Variables, []string, Handle, error) {
 	if !c.client {
-		if len(args) != 3 {
+		if len(args) != 2 {
 			return nil, nil, nil, fmt.Errorf("wrong #args: %s", c.Help())
 		}
 		return runServer("clock", args)
@@ -143,15 +126,15 @@
 		return `<name> <message>
 executes name.Echo(message)`
 	}
-	return `<root> <prefix> <suffix>
-runs a clock server with root as its root mountTable, Register(prefix...) and  Pubish(suffix)`
+	return `<root> <mountpoint>
+runs a clock server with root as its root mount table, mounted at <mountpoint>`
 }
 
 func (e *echo) Daemon() bool { return !e.client }
 
 func (e *echo) Run(args []string) (Variables, []string, Handle, error) {
 	if !e.client {
-		if len(args) != 3 {
+		if len(args) != 2 {
 			return nil, nil, nil, fmt.Errorf("wrong #args: %s", e.Help())
 		}
 		return runServer("echo", args)
@@ -175,8 +158,11 @@
 }
 
 func runServer(name string, args []string) (Variables, []string, Handle, error) {
-	env := []string{"NAMESPACE_ROOT=" + args[0]}
-	c, v, r, err := bbSpawn(name, args, env)
+	var env []string
+	if len(args[0]) > 0 {
+		env = append(env, "NAMESPACE_ROOT="+args[0])
+	}
+	c, v, r, err := bbSpawn(name, args[1:], env)
 	if err != nil {
 		return v, r, nil, err
 	}
diff --git a/runtimes/google/ipc/benchmarks/server.go b/runtimes/google/ipc/benchmarks/server.go
index d585d72..bd5eb0c 100644
--- a/runtimes/google/ipc/benchmarks/server.go
+++ b/runtimes/google/ipc/benchmarks/server.go
@@ -42,13 +42,13 @@
 	if err != nil {
 		vlog.Fatalf("NewServer failed: %v", err)
 	}
-	if err := server.Register("", ipc.SoloDispatcher(NewServerBenchmark(&impl{}), sflag.NewAuthorizerOrDie())); err != nil {
-		vlog.Fatalf("Register failed: %v", err)
-	}
 	ep, err := server.Listen(protocol, address)
 	if err != nil {
 		vlog.Fatalf("Listen failed: %v", err)
 	}
+	if err := server.Serve("", ipc.SoloDispatcher(NewServerBenchmark(&impl{}), sflag.NewAuthorizerOrDie())); err != nil {
+		vlog.Fatalf("Serve failed: %v", err)
+	}
 	return naming.JoinAddressName(ep.String(), ""), func() {
 		if err := server.Stop(); err != nil {
 			vlog.Fatalf("Stop() failed: %v", err)
diff --git a/runtimes/google/ipc/flow_test.go b/runtimes/google/ipc/flow_test.go
index e856eb3..7009258 100644
--- a/runtimes/google/ipc/flow_test.go
+++ b/runtimes/google/ipc/flow_test.go
@@ -105,22 +105,16 @@
 		err    error
 	}
 	tests := []testcase{
-		{"closure", "A", nil, nil, nil},
-		{"closure/foo", "B", nil, nil, errors.New("foo")},
-
-		{"echo", "A", v{""}, v{`method:"A",suffix:"",arg:""`}, nil},
-		{"echo", "B", v{"foo"}, v{`method:"B",suffix:"",arg:"foo"`}, nil},
-		{"echo/abc", "C", v{""}, v{`method:"C",suffix:"abc",arg:""`}, nil},
-		{"echo/abc", "D", v{"foo"}, v{`method:"D",suffix:"abc",arg:"foo"`}, nil},
+		{"echo", "A", v{""}, v{`method:"A",suffix:"echo",arg:""`}, nil},
+		{"echo", "B", v{"foo"}, v{`method:"B",suffix:"echo",arg:"foo"`}, nil},
+		{"echo/abc", "C", v{""}, v{`method:"C",suffix:"echo/abc",arg:""`}, nil},
+		{"echo/abc", "D", v{"foo"}, v{`method:"D",suffix:"echo/abc",arg:"foo"`}, nil},
 	}
 	name := func(t testcase) string {
 		return fmt.Sprintf("%s.%s%v", t.suffix, t.method, t.args)
 	}
 
-	disptrie := newDisptrie()
-	disptrie.Register("echo", testDisp{newEchoInvoker})
-	disptrie.Register("closure", testDisp{newClosureInvoker})
-	ipcServer := &server{disptrie: disptrie}
+	ipcServer := &server{disp: testDisp{newEchoInvoker}}
 	for _, test := range tests {
 		clientFlow, serverFlow := newTestFlows()
 		client := newFlowClient(clientFlow)
diff --git a/runtimes/google/ipc/full_test.go b/runtimes/google/ipc/full_test.go
index 3c68e79..86b5a18 100644
--- a/runtimes/google/ipc/full_test.go
+++ b/runtimes/google/ipc/full_test.go
@@ -202,31 +202,33 @@
 	return nil, nil
 }
 
-func (ns *namespace) SetRoots([]string) error {
+func (ns *namespace) SetRoots(...string) error {
 	panic("SetRoots not implemented")
 	return nil
 }
 
-func startServer(t *testing.T, serverID security.PrivateID, sm stream.Manager, ns naming.Namespace, ts interface{}) ipc.Server {
+func (ns *namespace) Roots() []string {
+	panic("Roots not implemented")
+	return nil
+}
+
+func startServer(t *testing.T, serverID security.PrivateID, sm stream.Manager, ns naming.Namespace, ts interface{}) (naming.Endpoint, ipc.Server) {
 	vlog.VI(1).Info("InternalNewServer")
 	server, err := InternalNewServer(InternalNewContext(), sm, ns, listenerID(serverID))
 	if err != nil {
 		t.Errorf("InternalNewServer failed: %v", err)
 	}
-	vlog.VI(1).Info("server.Register")
-	disp := testServerDisp{ts}
-	if err := server.Register("server", disp); err != nil {
-		t.Errorf("server.Register failed: %v", err)
-	}
 	vlog.VI(1).Info("server.Listen")
-	if _, err := server.Listen("tcp", "localhost:0"); err != nil {
+	ep, err := server.Listen("tcp", "localhost:0")
+	if err != nil {
 		t.Errorf("server.Listen failed: %v", err)
 	}
-	vlog.VI(1).Info("server.Publish")
-	if err := server.Publish("mountpoint"); err != nil {
+	vlog.VI(1).Info("server.Serve")
+	disp := testServerDisp{ts}
+	if err := server.Serve("mountpoint/server", disp); err != nil {
 		t.Errorf("server.Publish failed: %v", err)
 	}
-	return server
+	return ep, server
 }
 
 func verifyMount(t *testing.T, ns naming.Namespace, name string) {
@@ -243,28 +245,35 @@
 
 func stopServer(t *testing.T, server ipc.Server, ns naming.Namespace) {
 	vlog.VI(1).Info("server.Stop")
-	verifyMount(t, ns, "mountpoint/server")
+	n1 := "mountpoint/server"
+	n2 := "should_appear_in_mt/server"
+	verifyMount(t, ns, n1)
 
-	// Check that we can still publish.
-	server.Publish("should_appear_in_mt")
-	verifyMount(t, ns, "should_appear_in_mt/server")
+	// publish a second name
+	if err := server.Serve(n2, nil); err != nil {
+		t.Errorf("server.Serve failed: %v", err)
+	}
+	verifyMount(t, ns, n2)
 
 	if err := server.Stop(); err != nil {
 		t.Errorf("server.Stop failed: %v", err)
 	}
-	// Check that we can no longer publish after Stop.
-	server.Publish("should_not_appear_in_mt")
-	verifyMountMissing(t, ns, "should_not_appear_in_mt/server")
 
-	verifyMountMissing(t, ns, "mountpoint/server")
-	verifyMountMissing(t, ns, "should_appear_in_mt/server")
-	verifyMountMissing(t, ns, "should_not_appear_in_mt/server")
+	verifyMountMissing(t, ns, n1)
+	verifyMountMissing(t, ns, n2)
+
+	// Check that we can no longer serve after Stop.
+	err := server.Serve("name doesn't matter", nil)
+	if err == nil || err.Error() != "ipc: server is stopped" {
+		t.Errorf("either no error, or a wrong error was returned: %v", err)
+	}
 	vlog.VI(1).Info("server.Stop DONE")
 }
 
 type bundle struct {
 	client ipc.Client
 	server ipc.Server
+	ep     naming.Endpoint
 	ns     naming.Namespace
 	sm     stream.Manager
 }
@@ -277,7 +286,7 @@
 func createBundle(t *testing.T, clientID, serverID security.PrivateID, ts interface{}) (b bundle) {
 	b.sm = imanager.InternalNew(naming.FixedRoutingID(0x555555555))
 	b.ns = newNamespace()
-	b.server = startServer(t, serverID, b.sm, b.ns, ts)
+	b.ep, b.server = startServer(t, serverID, b.sm, b.ns, ts)
 	var err error
 	b.client, err = InternalNewClient(b.sm, b.ns, veyron2.LocalID(clientID))
 	if err != nil {
@@ -313,6 +322,53 @@
 	return err == nil || strings.Index(err.Error(), pattern) >= 0
 }
 
+func TestMultipleCallsToServe(t *testing.T) {
+	sm := imanager.InternalNew(naming.FixedRoutingID(0x555555555))
+	ns := newNamespace()
+	server, err := InternalNewServer(InternalNewContext(), sm, ns, listenerID(serverID))
+	if err != nil {
+		t.Errorf("InternalNewServer failed: %v", err)
+	}
+	_, err = server.Listen("tcp", "localhost:0")
+	if err != nil {
+		t.Errorf("server.Listen failed: %v", err)
+	}
+
+	disp := &testServerDisp{&testServer{}}
+	if err := server.Serve("mountpoint/server", disp); err != nil {
+		t.Errorf("server.Publish failed: %v", err)
+	}
+
+	n1 := "mountpoint/server"
+	n2 := "should_appear_in_mt/server"
+	n3 := "should_appear_in_mt/server"
+	n4 := "should_not_appear_in_mt/server"
+
+	verifyMount(t, ns, n1)
+
+	if err := server.Serve(n2, disp); err != nil {
+		t.Errorf("server.Serve failed: %v", err)
+	}
+	if err := server.Serve(n3, nil); err != nil {
+		t.Errorf("server.Serve failed: %v", err)
+	}
+	verifyMount(t, ns, n2)
+	verifyMount(t, ns, n3)
+
+	if err := server.Serve(n4, &testServerDisp{&testServer{}}); err == nil {
+		t.Errorf("server.Serve should have failed")
+	}
+	verifyMountMissing(t, ns, n4)
+
+	if err := server.Stop(); err != nil {
+		t.Errorf("server.Stop failed: %v", err)
+	}
+
+	verifyMountMissing(t, ns, n1)
+	verifyMountMissing(t, ns, n2)
+	verifyMountMissing(t, ns, n3)
+}
+
 func TestStartCall(t *testing.T) {
 	authorizeErr := "not authorized because"
 	nameErr := "does not match the provided pattern"
@@ -355,7 +411,7 @@
 	ns := newNamespace()
 	for _, test := range tests {
 		name := fmt.Sprintf("(clientID:%q serverID:%q)", test.clientID, test.serverID)
-		server := startServer(t, test.serverID, mgr, ns, &testServer{})
+		_, server := startServer(t, test.serverID, mgr, ns, &testServer{})
 		client, err := InternalNewClient(mgr, ns, veyron2.LocalID(test.clientID))
 		if err != nil {
 			t.Errorf("%s: Client creation failed: %v", name, err)
@@ -732,15 +788,16 @@
 	publisher.AddServer("/@2@tcp@localhost:10000@@1000000@2000000@@")
 	publisher.AddServer("/@2@tcp@localhost:10001@@2000000@3000000@@")
 
-	_, err := b.client.StartCall(&fakeContext{}, "incompatible/server/suffix", "Echo", []interface{}{"foo"})
+	_, err := b.client.StartCall(&fakeContext{}, "incompatible/suffix", "Echo", []interface{}{"foo"})
 	if !strings.Contains(err.Error(), version.NoCompatibleVersionErr.Error()) {
 		t.Errorf("Expected error %v, found: %v", version.NoCompatibleVersionErr, err)
 	}
 
 	// Now add a server with a compatible endpoint and try again.
-	b.server.Publish("incompatible")
+	publisher.AddServer("/" + b.ep.String())
+	publisher.AddName("incompatible")
 
-	call, err := b.client.StartCall(&fakeContext{}, "incompatible/server/suffix", "Echo", []interface{}{"foo"})
+	call, err := b.client.StartCall(&fakeContext{}, "incompatible/suffix", "Echo", []interface{}{"foo"})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -785,7 +842,7 @@
 			server.Stop()
 			continue
 		}
-		if err := server.Publish("mountpoint"); err != nil {
+		if err := server.Serve("mountpoint", &testServerDisp{}); err != nil {
 			t.Errorf("server.Publish failed: %v", err)
 			server.Stop()
 			continue
@@ -835,7 +892,7 @@
 	if err != nil {
 		t.Fatalf("inaming.NewEndpoint(%q): %v", addr, err)
 	}
-	serverName := naming.JoinAddressName(ep.String(), "server/suffix")
+	serverName := naming.JoinAddressName(ep.String(), "suffix")
 	makeCall := func() (string, error) {
 		call, err := b.client.StartCall(&fakeContext{}, serverName, "Echo", []interface{}{"bratman"})
 		if err != nil {
@@ -913,9 +970,6 @@
 		t.Fatal(err)
 	}
 	defer server.Stop()
-	if err := server.Register("server", testServerDisp{&testServer{}}); err != nil {
-		t.Fatal(err)
-	}
 
 	name := "mountpoint/server/suffix"
 	makeCall := func() (string, error) {
@@ -937,7 +991,7 @@
 	if _, err := server.Listen(inaming.Network, "proxy"); err != nil {
 		t.Fatal(err)
 	}
-	if err := server.Publish("mountpoint"); err != nil {
+	if err := server.Serve("mountpoint/server", testServerDisp{&testServer{}}); err != nil {
 		t.Fatal(err)
 	}
 	verifyMount(t, ns, name)
@@ -998,7 +1052,7 @@
 		vlog.Fatalf("InternalNewServer failed: %v", err)
 	}
 	disp := testServerDisp{new(testServer)}
-	if err := server.Register("server", disp); err != nil {
+	if err := server.Serve("server", disp); err != nil {
 		vlog.Fatalf("server.Register failed: %v", err)
 	}
 	ep, err := server.Listen("tcp", argv[0])
diff --git a/runtimes/google/ipc/server.go b/runtimes/google/ipc/server.go
index fb4406d..f162fdf 100644
--- a/runtimes/google/ipc/server.go
+++ b/runtimes/google/ipc/server.go
@@ -36,10 +36,10 @@
 	sync.Mutex
 	ctx              context.T                // context used by the server to make internal RPCs.
 	streamMgr        stream.Manager           // stream manager to listen for new flows.
-	disptrie         *disptrie                // dispatch trie for method dispatching.
 	publisher        publisher.Publisher      // publisher to publish mounttable mounts.
 	listenerOpts     []stream.ListenerOpt     // listener opts passed to Listen.
 	listeners        map[stream.Listener]bool // listeners created by Listen.
+	disp             ipc.Dispatcher           // dispatcher to serve RPCs
 	active           sync.WaitGroup           // active goroutines we've spawned.
 	stopped          bool                     // whether the server has been stopped.
 	stoppedChan      chan struct{}            // closed when the server has been stopped.
@@ -53,7 +53,6 @@
 	s := &server{
 		ctx:         ctx,
 		streamMgr:   streamMgr,
-		disptrie:    newDisptrie(),
 		publisher:   publisher.New(ctx, ns, publishPeriod),
 		listeners:   make(map[stream.Listener]bool),
 		stoppedChan: make(chan struct{}),
@@ -73,15 +72,6 @@
 	return s, nil
 }
 
-func (s *server) Register(prefix string, disp ipc.Dispatcher) error {
-	s.Lock()
-	defer s.Unlock()
-	if s.stopped {
-		return errServerStopped
-	}
-	return s.disptrie.Register(prefix, disp)
-}
-
 func (s *server) Published() ([]string, error) {
 	s.Lock()
 	defer s.Unlock()
@@ -246,8 +236,21 @@
 	}
 }
 
-func (s *server) Publish(name string) error {
-	s.publisher.AddName(name)
+func (s *server) Serve(name string, disp ipc.Dispatcher) error {
+	s.Lock()
+	defer s.Unlock()
+	if s.stopped {
+		return errServerStopped
+	}
+	if s.disp != nil && disp != nil && s.disp != disp {
+		return fmt.Errorf("attempt to change dispatcher")
+	}
+	if disp != nil {
+		s.disp = disp
+	}
+	if len(name) > 0 {
+		s.publisher.AddName(name)
+	}
 	return nil
 }
 
@@ -297,39 +300,37 @@
 
 	// Wait for the publisher and active listener + flows to finish.
 	s.active.Wait()
-
-	// Once all outstanding requests are done, we can clean up the rest of
-	// the state.
-	s.disptrie.Stop()
-
+	s.Lock()
+	s.disp = nil
+	s.Unlock()
 	return firstErr
 }
 
 // flowServer implements the RPC server-side protocol for a single RPC, over a
 // flow that's already connected to the client.
 type flowServer struct {
-	disptrie *disptrie    // dispatch trie
-	server   ipc.Server   // ipc.Server that this flow server belongs to
-	dec      *vom.Decoder // to decode requests and args from the client
-	enc      *vom.Encoder // to encode responses and results to the client
-	flow     stream.Flow  // underlying flow
+	disp   ipc.Dispatcher
+	server ipc.Server   // ipc.Server that this flow server belongs to
+	dec    *vom.Decoder // to decode requests and args from the client
+	enc    *vom.Encoder // to encode responses and results to the client
+	flow   stream.Flow  // underlying flow
 	// Fields filled in during the server invocation.
 
 	// authorizedRemoteID is the PublicID obtained after authorizing the remoteID
 	// of the underlying flow for the current request context.
-	authorizedRemoteID   security.PublicID
-	blessing             security.PublicID
-	method, name, suffix string
-	label                security.Label
-	discharges           security.CaveatDischargeMap
-	deadline             time.Time
-	endStreamArgs        bool // are the stream args at EOF?
+	authorizedRemoteID security.PublicID
+	blessing           security.PublicID
+	method, suffix     string
+	label              security.Label
+	discharges         security.CaveatDischargeMap
+	deadline           time.Time
+	endStreamArgs      bool // are the stream args at EOF?
 }
 
 func newFlowServer(flow stream.Flow, server *server) *flowServer {
 	return &flowServer{
-		server:   server,
-		disptrie: server.disptrie,
+		server: server,
+		disp:   server.disp,
 		// TODO(toddw): Support different codecs
 		dec:  vom.NewDecoder(flow),
 		enc:  vom.NewEncoder(flow),
@@ -449,10 +450,10 @@
 		// should servers be able to assume that a blessing is something that does not
 		// have the authorizations that the server's own identity has?
 	}
+
 	// Lookup the invoker.
-	invoker, auth, name, suffix, verr := fs.lookup(req.Suffix)
-	fs.name = name
-	fs.suffix = suffix
+	invoker, auth, suffix, verr := fs.lookup(req.Suffix)
+	fs.suffix = suffix // with leading /'s stripped
 	if verr != nil {
 		return nil, verr
 	}
@@ -479,7 +480,6 @@
 				LocalID:    fs.flow.LocalID(),
 				RemoteID:   fs.flow.RemoteID(),
 				Method:     fs.method,
-				Name:       fs.name,
 				Suffix:     fs.suffix,
 				Discharges: fs.discharges,
 				Label:      fs.label})); err != nil {
@@ -499,20 +499,18 @@
 // name.  The name is stripped of any leading slashes, and the invoker is looked
 // up in the server's dispatcher.  The (stripped) name and dispatch suffix are
 // also returned.
-func (fs *flowServer) lookup(name string) (ipc.Invoker, security.Authorizer, string, string, verror.E) {
+func (fs *flowServer) lookup(name string) (ipc.Invoker, security.Authorizer, string, verror.E) {
 	name = strings.TrimLeft(name, "/")
-	disps, suffix := fs.disptrie.Lookup(name)
-	for _, disp := range disps {
-		invoker, auth, err := disp.Lookup(suffix)
+	if fs.disp != nil {
+		invoker, auth, err := fs.disp.Lookup(name)
 		switch {
 		case err != nil:
-			return nil, nil, "", "", verror.Convert(err)
+			return nil, nil, "", verror.Convert(err)
 		case invoker != nil:
-			return invoker, auth, name, suffix, nil
+			return invoker, auth, name, nil
 		}
-		// The dispatcher doesn't handle this suffix, try the next one.
 	}
-	return nil, nil, "", "", verror.NotFoundf(fmt.Sprintf("ipc: dispatcher not found for %q", name))
+	return nil, nil, "", verror.NotFoundf(fmt.Sprintf("ipc: dispatcher not found for %q", name))
 }
 
 func (fs *flowServer) authorize(auth security.Authorizer) error {
@@ -561,18 +559,23 @@
 
 // Implementations of ipc.ServerContext methods.
 
-func (fs *flowServer) Server() ipc.Server                            { return fs.server }
-func (fs *flowServer) Method() string                                { return fs.method }
-func (fs *flowServer) Name() string                                  { return fs.name }
-func (fs *flowServer) Suffix() string                                { return fs.suffix }
-func (fs *flowServer) Label() security.Label                         { return fs.label }
 func (fs *flowServer) CaveatDischarges() security.CaveatDischargeMap { return fs.discharges }
-func (fs *flowServer) LocalID() security.PublicID                    { return fs.flow.LocalID() }
-func (fs *flowServer) RemoteID() security.PublicID                   { return fs.authorizedRemoteID }
-func (fs *flowServer) Deadline() time.Time                           { return fs.deadline }
-func (fs *flowServer) Blessing() security.PublicID                   { return fs.blessing }
-func (fs *flowServer) LocalEndpoint() naming.Endpoint                { return fs.flow.LocalEndpoint() }
-func (fs *flowServer) RemoteEndpoint() naming.Endpoint               { return fs.flow.RemoteEndpoint() }
+
+func (fs *flowServer) Server() ipc.Server { return fs.server }
+func (fs *flowServer) Method() string     { return fs.method }
+
+// TODO(cnicolaou): remove Name from ipc.ServerContext and all of
+// its implementations
+func (fs *flowServer) Name() string          { return fs.suffix }
+func (fs *flowServer) Suffix() string        { return fs.suffix }
+func (fs *flowServer) Label() security.Label { return fs.label }
+
+func (fs *flowServer) LocalID() security.PublicID      { return fs.flow.LocalID() }
+func (fs *flowServer) RemoteID() security.PublicID     { return fs.authorizedRemoteID }
+func (fs *flowServer) Deadline() time.Time             { return fs.deadline }
+func (fs *flowServer) Blessing() security.PublicID     { return fs.blessing }
+func (fs *flowServer) LocalEndpoint() naming.Endpoint  { return fs.flow.LocalEndpoint() }
+func (fs *flowServer) RemoteEndpoint() naming.Endpoint { return fs.flow.RemoteEndpoint() }
 
 func (fs *flowServer) IsClosed() bool {
 	return fs.flow.IsClosed()
diff --git a/runtimes/google/naming/namespace/all_test.go b/runtimes/google/naming/namespace/all_test.go
index a628069..4db264c 100644
--- a/runtimes/google/naming/namespace/all_test.go
+++ b/runtimes/google/naming/namespace/all_test.go
@@ -1,7 +1,10 @@
 package namespace_test
 
 import (
+	"reflect"
+	"runtime"
 	"runtime/debug"
+	"sort"
 	"testing"
 	"time"
 
@@ -22,9 +25,19 @@
 	t.Fatal(string(debug.Stack()))
 }
 
+func compare(t *testing.T, caller, name string, got, want []string) {
+	if len(got) != len(want) {
+		boom(t, "%s: %q returned wrong # servers: got %v, want %v, servers: got %v, want %v", caller, name, len(got), len(want), got, want)
+	}
+	sort.Strings(got)
+	sort.Strings(want)
+	if !reflect.DeepEqual(got, want) {
+		boom(t, "%s: %q: got %v, want %v", caller, name, got, want)
+	}
+}
+
 func doGlob(t *testing.T, ctx context.T, ns naming.Namespace, pattern string) []string {
 	var replies []string
-
 	rc, err := ns.Glob(ctx, pattern)
 	if err != nil {
 		boom(t, "Glob(%s): %s", pattern, err)
@@ -35,27 +48,6 @@
 	return replies
 }
 
-func checkMatch(t *testing.T, pattern string, expected []string, got []string) {
-L:
-	for _, e := range expected {
-		for _, g := range got {
-			if g == e {
-				continue L
-			}
-		}
-		boom(t, "Glob %s expected %v got %v", pattern, expected, got)
-	}
-L2:
-	for _, g := range got {
-		for _, e := range expected {
-			if g == e {
-				continue L2
-			}
-		}
-		boom(t, "Glob %s expected %v got %v", pattern, expected, got)
-	}
-}
-
 type testServer struct{}
 
 func (*testServer) KnockKnock(call ipc.ServerCall) string {
@@ -78,8 +70,423 @@
 	}
 }
 
+func testResolveToMountTable(t *testing.T, r veyron2.Runtime, ns naming.Namespace, name string, want ...string) {
+	servers, err := ns.ResolveToMountTable(r.NewContext(), name)
+	if err != nil {
+		boom(t, "Failed to ResolveToMountTable %q: %s", name, err)
+	}
+	compare(t, "ResolveToMoutTable", name, servers, want)
+}
+
+func testResolve(t *testing.T, r veyron2.Runtime, ns naming.Namespace, name string, want ...string) {
+	servers, err := ns.Resolve(r.NewContext(), name)
+	if err != nil {
+		boom(t, "Failed to Resolve %q: %s", name, err)
+	}
+	compare(t, "Resolve", name, servers, want)
+}
+
+func testUnresolve(t *testing.T, r veyron2.Runtime, ns naming.Namespace, name string, want ...string) {
+	servers, err := ns.Unresolve(r.NewContext(), name)
+	if err != nil {
+		boom(t, "Failed to Resolve %q: %s", name, err)
+	}
+	compare(t, "Unresolve", name, servers, want)
+}
+
+type serverEntry struct {
+	mountPoint string
+	server     ipc.Server
+	endpoint   naming.Endpoint
+	name       string
+}
+
+func runServer(t *testing.T, sr veyron2.Runtime, disp ipc.Dispatcher, mountPoint string) *serverEntry {
+	return run(t, sr, disp, mountPoint, false)
+}
+
+func runMT(t *testing.T, sr veyron2.Runtime, mountPoint string) *serverEntry {
+	mt, err := service.NewMountTable("")
+	if err != nil {
+		boom(t, "NewMountTable returned error: %v", err)
+	}
+	return run(t, sr, mt, mountPoint, true)
+}
+
+func run(t *testing.T, sr veyron2.Runtime, disp ipc.Dispatcher, mountPoint string, mt bool) *serverEntry {
+	s, err := sr.NewServer(veyron2.ServesMountTableOpt(mt))
+	if err != nil {
+		boom(t, "r.NewServer: %s", err)
+	}
+	// Add a mount table server.
+	// Start serving on a loopback address.
+	ep, err := s.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		boom(t, "Failed to Listen: %s", err)
+	}
+	if err := s.Serve(mountPoint, disp); err != nil {
+		boom(t, "Failed to serve mount table at %s: %s", mountPoint, err)
+	}
+	name := naming.JoinAddressName(ep.String(), "")
+	if !mt {
+		name = name + "//"
+	}
+	return &serverEntry{mountPoint: mountPoint, server: s, endpoint: ep, name: name}
+}
+
+const (
+	mt1MP = "mt1"
+	mt2MP = "mt2"
+	mt3MP = "mt3"
+	mt4MP = "mt4"
+	mt5MP = "mt5"
+	j1MP  = "joke1"
+	j2MP  = "joke2"
+	j3MP  = "joke3"
+
+	ttl = 100 * time.Second
+)
+
+// runMountTables creates a root mountable with some mount tables mounted
+// in it: mt{1,2,3,4,5}
+func runMountTables(t *testing.T, r veyron2.Runtime) (*serverEntry, map[string]*serverEntry) {
+	root := runMT(t, r, "")
+	r.Namespace().SetRoots(root.name)
+	t.Logf("mountTable %q -> %s", root.mountPoint, root.endpoint)
+
+	mps := make(map[string]*serverEntry)
+	for _, mp := range []string{mt1MP, mt2MP, mt3MP, mt4MP, mt5MP} {
+		m := runMT(t, r, mp)
+		t.Logf("mountTable %q -> %s", mp, m.endpoint)
+		mps[mp] = m
+	}
+	return root, mps
+}
+
+// createNamespace creates a hiearachy of mounttables and servers
+// as follows:
+// /mt1, /mt2, /mt3, /mt4, /mt5, /joke1, /joke2, /joke3.
+// That is, mt1 is a mount table mounted in the root mount table,
+// joke1 is a server mounted in the root mount table.
+func createNamespace(t *testing.T, r veyron2.Runtime) (*serverEntry, map[string]*serverEntry, map[string]*serverEntry, func()) {
+	root, mts := runMountTables(t, r)
+	jokes := make(map[string]*serverEntry)
+	// Let's run some non-mount table services.
+	for _, j := range []string{j1MP, j2MP, j3MP} {
+		disp := ipc.SoloDispatcher(&testServer{}, nil)
+		jokes[j] = runServer(t, r, disp, j)
+	}
+	return root, mts, jokes, func() {
+		for _, s := range jokes {
+			s.server.Stop()
+		}
+		for _, s := range mts {
+			s.server.Stop()
+		}
+		root.server.Stop()
+	}
+}
+
+// runNestedMountTables creates some nested mount tables in the hierarchy
+// created by createNamespace as follows:
+// /mt4/foo, /mt4/foo/bar and /mt4/baz where foo, bar and baz are mount tables.
+func runNestedMountTables(t *testing.T, r veyron2.Runtime, mts map[string]*serverEntry) {
+	ns, ctx := r.Namespace(), r.NewContext()
+	// Set up some nested mounts and verify resolution.
+	for _, m := range []string{"mt4/foo", "mt4/foo/bar"} {
+		mts[m] = runMT(t, r, m)
+	}
+
+	// Use a global name for a mount, rather than a relative one.
+	// We directly mount baz into the mt4/foo mount table.
+	globalMP := naming.JoinAddressName(mts["mt4/foo"].name, "baz")
+	mts["baz"] = runMT(t, r, "baz")
+	if err := ns.Mount(ctx, globalMP, mts["baz"].name, ttl); err != nil {
+		boom(t, "Failed to Mount %s: %s", globalMP, err)
+	}
+}
+
+// TestNamespaceCommon tests common use of the Namespace library
+// against a root mount table and some mount tables mounted on it.
+func TestNamespaceCommon(t *testing.T) {
+	// We need the default runtime for the server-side mounttable code
+	// which references rt.R() to create new endpoints
+	rt.Init()
+	r, _ := rt.New() // We use a different runtime for the client side.
+	root, mts, jokes, stopper := createNamespace(t, r)
+	defer stopper()
+	ns := r.Namespace()
+
+	// All of the initial mounts are served by the root mounttable
+	// and hence ResolveToMountTable should return the root mountable
+	// as the address portion of the terminal name for those mounttables.
+	testResolveToMountTable(t, r, ns, "", root.name)
+	for _, m := range []string{mt2MP, mt3MP, mt5MP} {
+		rootMT := naming.MakeTerminal(naming.Join(root.name, m))
+		// All of these mount tables are hosted by the root mount table
+		testResolveToMountTable(t, r, ns, m, rootMT)
+		testResolveToMountTable(t, r, ns, "//"+m, rootMT)
+
+		// The server registered for each mount point is a mount table
+		testResolve(t, r, ns, m, mts[m].name)
+
+		// ResolveToMountTable will walk through to the sub MountTables
+		mtbar := naming.Join(m, "bar")
+		subMT := naming.MakeTerminal(naming.Join(mts[m].name, "bar"))
+		testResolveToMountTable(t, r, ns, mtbar, subMT)
+
+		// ResolveToMountTable will not walk through if the name is terminal
+		testResolveToMountTable(t, r, ns, "//"+mtbar, naming.Join(rootMT, "bar"))
+	}
+
+	for _, j := range []string{j1MP, j2MP, j3MP} {
+		testResolve(t, r, ns, j, jokes[j].name)
+	}
+}
+
+// TestNamespaceDetails tests more detailed use of the Namespace library,
+// including the intricacies of // meaning and placement.
+func TestNamespaceDetails(t *testing.T) {
+	sr := rt.Init()
+	r, _ := rt.New() // We use a different runtime for the client side.
+	root, mts, _, stopper := createNamespace(t, sr)
+	defer stopper()
+
+	ns := r.Namespace()
+	ns.SetRoots(root.name)
+
+	// Mount using a relative name starting with //.
+	// This means don't walk out of the namespace's root mount table
+	// even if there is already something mounted at mt2. Thus, the example
+	// below will fail.
+	mt3Server := mts[mt3MP].name
+	mt2a := "//mt2/a"
+	if err := ns.Mount(r.NewContext(), mt2a, mt3Server, ttl); err != naming.ErrNoSuchName {
+		boom(t, "Successfully mounted %s - expected an err %v, not %v", mt2a, naming.ErrNoSuchName, err)
+	}
+
+	// Mount using the relative name not starting with //.
+	// This means walk through mt2 if it already exists and mount within
+	// the lower level mount table, if the name doesn't exist we'll create
+	// a new name for it.
+	mt2a = "mt2/a"
+	if err := ns.Mount(r.NewContext(), mt2a, mt3Server, ttl); err != nil {
+		boom(t, "Failed to Mount %s: %s", mt2a, err)
+	}
+
+	mt2mt := naming.MakeTerminal(naming.Join(mts[mt2MP].name, "a"))
+	// The mt2/a is served by the mt2 mount table
+	testResolveToMountTable(t, r, ns, mt2a, mt2mt)
+	// The server for mt2a is mt3server from the second mount above.
+	testResolve(t, r, ns, mt2a, mt3Server)
+
+	// Using a terminal or non-terminal name makes no difference if the
+	// mount is directed to the root name server (since that's the root
+	// for the namespace for this process) and the name exists within
+	// that mount table. In both cases, the server will be added to the
+	// set of mount table servers for that name.
+	for _, mp := range []struct{ name, server string }{
+		{"mt2", mts[mt4MP].name},
+		{"//mt2", mts[mt5MP].name},
+	} {
+		if err := ns.Mount(r.NewContext(), mp.name, mp.server, ttl); err != nil {
+			boom(t, "Failed to Mount %s: %s", mp.name, err)
+		}
+	}
+
+	// We now have 3 mount tables prepared to serve mt2/a
+	testResolveToMountTable(t, r, ns, "mt2/a",
+		mts[mt2MP].name+"//a",
+		mts[mt4MP].name+"//a",
+		mts[mt5MP].name+"//a")
+	testResolve(t, r, ns, "mt2", mts[mt2MP].name, mts[mt4MP].name, mts[mt5MP].name)
+}
+
+// TestNestedMounts tests some more deeply nested mounts
+func TestNestedMounts(t *testing.T) {
+	sr := rt.Init()
+	r, _ := rt.New() // We use a different runtime for the client side.
+	root, mts, _, stopper := createNamespace(t, sr)
+	runNestedMountTables(t, sr, mts)
+	defer stopper()
+
+	ns := r.Namespace()
+	ns.SetRoots(root.name)
+
+	// Set up some nested mounts and verify resolution.
+	for _, m := range []string{"mt4/foo", "mt4/foo/bar"} {
+		testResolve(t, r, ns, m, mts[m].name)
+	}
+
+	testResolveToMountTable(t, r, ns, "mt4/foo",
+		mts[mt4MP].name+"//foo")
+	testResolveToMountTable(t, r, ns, "mt4/foo/bar",
+		mts["mt4/foo"].name+"//bar")
+	testResolveToMountTable(t, r, ns, "mt4/foo/baz", mts["mt4/foo"].name+"//baz")
+}
+
+// TestServers tests invoking RPCs on simple servers
+func TestServers(t *testing.T) {
+	sr := rt.Init()
+	r, _ := rt.New() // We use a different runtime for the client side.
+	root, mts, jokes, stopper := createNamespace(t, sr)
+	defer stopper()
+	ns := r.Namespace()
+	ns.SetRoots(root.name)
+
+	// Let's run some non-mount table servic
+	for _, j := range []string{j1MP, j2MP, j3MP} {
+		testResolve(t, r, ns, j, jokes[j].name)
+		knockKnock(t, r, j)
+		globalName := naming.JoinAddressName(mts["mt4"].name, j)
+		disp := ipc.SoloDispatcher(&testServer{}, nil)
+		gj := "g_" + j
+		jokes[gj] = runServer(t, r, disp, globalName)
+		testResolve(t, r, ns, "mt4/"+j, jokes[gj].name)
+		knockKnock(t, r, "mt4/"+j)
+		testResolveToMountTable(t, r, ns, "mt4/"+j, naming.MakeTerminal(globalName))
+		testResolveToMountTable(t, r, ns, "mt4/"+j+"/garbage", naming.MakeTerminal(globalName+"/garbage"))
+	}
+}
+
+// TestGlob tests some glob patterns.
+func TestGlob(t *testing.T) {
+	sr := rt.Init()
+	r, _ := rt.New() // We use a different runtime for the client side.
+	root, mts, _, stopper := createNamespace(t, sr)
+	runNestedMountTables(t, sr, mts)
+	defer stopper()
+	ns := r.Namespace()
+	ns.SetRoots(root.name)
+
+	tln := []string{"baz", "mt1", "mt2", "mt3", "mt4", "mt5", "joke1", "joke2", "joke3"}
+	barbaz := []string{"mt4/foo/bar", "mt4/foo/baz"}
+	foo := append([]string{"mt4/foo"}, barbaz...)
+	// Try various globs.
+	globTests := []struct {
+		pattern  string
+		expected []string
+	}{
+		{"*", tln},
+		// TODO(cnicolaou): the glob that doesn't match a name should fail.
+		//
+		{"x", []string{"x"}},
+		{"m*", []string{"mt1", "mt2", "mt3", "mt4", "mt5"}},
+		{"mt[2,3]", []string{"mt2", "mt3"}},
+		{"*z", []string{"baz"}},
+		{"...", append(append(tln, foo...), "")},
+		{"*/...", append(tln, foo...)},
+		{"*/foo/*", barbaz},
+		{"*/*/*z", []string{"mt4/foo/baz"}},
+		{"*/f??/*z", []string{"mt4/foo/baz"}},
+	}
+	for _, test := range globTests {
+		out := doGlob(t, r, ns, test.pattern)
+		compare(t, "Glob", test.pattern, test.expected, out)
+	}
+}
+
+func TestCycles(t *testing.T) {
+	t.Skip() // Remove when the bug is fixed.
+
+	sr := rt.Init()
+	r, _ := rt.New() // We use a different runtime for the client side.
+	defer r.Shutdown()
+
+	root, _, _, stopper := createNamespace(t, sr)
+	defer stopper()
+	ns := r.Namespace()
+	ns.SetRoots(root.name)
+
+	c1 := runMT(t, r, "c1")
+	c2 := runMT(t, r, "c2")
+	c3 := runMT(t, r, "c3")
+	defer c1.server.Stop()
+	defer c2.server.Stop()
+	defer c3.server.Stop()
+
+	m := "c1/c2"
+	if err := ns.Mount(r.NewContext(), m, c1.name, ttl); err != nil {
+		boom(t, "Failed to Mount %s: %s", "c1/c2", err)
+	}
+
+	m = "c1/c2/c3"
+	if err := ns.Mount(r.NewContext(), m, c3.name, ttl); err != nil {
+		boom(t, "Failed to Mount %s: %s", m, err)
+	}
+
+	m = "c1/c3/c4"
+	if err := ns.Mount(r.NewContext(), m, c1.name, ttl); err != nil {
+		boom(t, "Failed to Mount %s: %s", m, err)
+	}
+
+	testResolve(t, r, ns, "c1", c1.name)
+	testResolve(t, r, ns, "c1/c2", c1.name)
+	testResolve(t, r, ns, "c1/c3", c3.name)
+	testResolve(t, r, ns, "c1/c3/c4", c1.name)
+	testResolve(t, r, ns, "c1/c3/c4/c3/c4", c1.name)
+	cycle := "c3/c4"
+	for i := 0; i < 40; i++ {
+		cycle += "/c3/c4"
+	}
+	if _, err := ns.Resolve(r, "c1/"+cycle); err.Error() != "Resolution depth exceeded" {
+		boom(t, "Failed to detect cycle")
+	}
+
+	// Remove the timeout when the bug is fixed, right now, this just
+	// finishes the test immediately. Add a comparison for the expected
+	// output from glob also.
+	ch := make(chan struct{})
+	go func() {
+		doGlob(t, r, ns, "c1/...")
+		close(ch)
+	}()
+	select {
+	case <-ch:
+	case <-time.After(time.Millisecond * 100):
+		t.Errorf("glob timedout")
+	}
+}
+
+func TestUnresolve(t *testing.T) {
+	// TODO(cnicolaou): move unresolve tests into this test, right now,
+	// that's annoying because the stub compiler has some blocking bugs and the
+	// Unresolve functionality is partially implemented in the stubs.
+	t.Skip()
+	sr := rt.Init()
+	r, _ := rt.New() // We use a different runtime for the client side.
+	defer r.Shutdown()
+	root, mts, jokes, stopper := createNamespace(t, sr)
+	runNestedMountTables(t, sr, mts)
+	defer stopper()
+	ns := r.Namespace()
+	ns.SetRoots(root.name)
+
+	vlog.Infof("Glob: %v", doGlob(t, r, ns, "*"))
+	testResolve(t, r, ns, "joke1", jokes["joke1"].name)
+	testUnresolve(t, r, ns, "joke1", "")
+}
+
+// TestGoroutineLeaks tests for leaking goroutines - we have many:-(
+func TestGoroutineLeaks(t *testing.T) {
+	t.Skip()
+	sr := rt.Init()
+	r, _ := rt.New() // We use a different runtime for the client side.
+	defer r.Shutdown()
+	_, _, _, stopper := createNamespace(t, sr)
+	defer func() {
+		vlog.Infof("%d goroutines:", runtime.NumGoroutine())
+	}()
+	defer stopper()
+	defer func() {
+		vlog.Infof("%d goroutines:", runtime.NumGoroutine())
+	}()
+	//panic("this will show up lots of goroutine+channel leaks!!!!")
+}
+
 func TestBadRoots(t *testing.T) {
 	r, _ := rt.New()
+	defer r.Shutdown()
 	if _, err := namespace.New(r); err != nil {
 		t.Errorf("namespace.New should not have failed with no roots")
 	}
@@ -87,264 +494,3 @@
 		t.Errorf("namespace.New should have failed with an unrooted name")
 	}
 }
-
-const (
-	mt1Prefix = "mt1"
-	mt2Prefix = "mt2"
-	mt3Prefix = "mt3"
-	mt4Prefix = "mt4"
-	mt5Prefix = "mt5"
-)
-
-func testResolveToMountTable(t *testing.T, ctx context.T, mt naming.Namespace, name, want string) {
-	servers, err := mt.ResolveToMountTable(ctx, name)
-	if err != nil {
-		boom(t, "Failed to ResolveToMountTable %q: %s", name, err)
-	}
-	if len(servers) != 1 || servers[0] != want {
-		boom(t, "ResolveToMountTable %q returned wrong servers: got %v, want %v", name, servers, want)
-	}
-}
-
-func testResolve(t *testing.T, ctx context.T, mt naming.Namespace, name, want string) {
-	servers, err := mt.Resolve(ctx, name)
-	if err != nil {
-		boom(t, "Failed to Resolve %q: %s", name, err)
-	}
-	if len(servers) != 1 || servers[0] != want {
-		boom(t, "Resolve %q returned wrong servers: got %v, want %v", name, servers, want)
-	}
-}
-
-func newMountTable(t *testing.T) ipc.Dispatcher {
-	mt, err := service.NewMountTable("")
-	if err != nil {
-		boom(t, "NewMountTable returned error: %v", err)
-	}
-	return mt
-}
-
-func runServer(t *testing.T) (ipc.Server, naming.Endpoint) {
-	// We are also running a server on this runtime using stubs so we must
-	// use rt.Init(). If the server were in a separate address as per usual,
-	// this wouldn't be needed and we could use rt.New.
-	sr := rt.Init()
-	vlog.Infof("TestNamespace")
-	server, err := sr.NewServer()
-	if err != nil {
-		boom(t, "r.NewServer: %s", err)
-	}
-
-	// Add some mount table servers.
-	if err := server.Register(mt1Prefix, newMountTable(t)); err != nil {
-		boom(t, "Failed to register mount table: %s", err)
-	}
-
-	if err := server.Register(mt2Prefix, newMountTable(t)); err != nil {
-		boom(t, "Failed to register mount table: %s", err)
-	}
-
-	if err := server.Register(mt3Prefix, newMountTable(t)); err != nil {
-		boom(t, "Failed to register mount table: %s", err)
-	}
-
-	if err := server.Register(mt4Prefix, newMountTable(t)); err != nil {
-		boom(t, "Failed to register mount table: %s", err)
-	}
-
-	if err := server.Register(mt5Prefix, newMountTable(t)); err != nil {
-		boom(t, "Failed to register mount table: %s", err)
-	}
-
-	// Add a few simple services.
-	if err := server.Register("joke1", ipc.SoloDispatcher(new(testServer), nil)); err != nil {
-		boom(t, "Failed to register test service: %s", err)
-	}
-	if err := server.Register("joke2", ipc.SoloDispatcher(new(testServer), nil)); err != nil {
-		boom(t, "Failed to register test service: %s", err)
-	}
-	if err := server.Register("joke3", ipc.SoloDispatcher(new(testServer), nil)); err != nil {
-		boom(t, "Failed to register test service: %s", err)
-	}
-
-	// Start serving on a loopback address.
-	ep, err := server.Listen("tcp", "127.0.0.1:0")
-	if err != nil {
-		boom(t, "Failed to Listen: %s", err)
-	}
-	t.Logf("endpoint %s", ep)
-	return server, ep
-}
-
-func TestNamespace(t *testing.T) {
-	// Run a MountTable server, which is serving MountTables on:
-	// /<estr>/{mt1,mt2,mt3,mt4,mt5}
-	server, ep := runServer(t)
-	defer server.Stop()
-
-	estr := ep.String()
-
-	// Run a client, creating a new runtime for it and intializing its
-	// namespace root to point to the server created above on /<ep>/mt1.
-	// This means that any relative names mounted using this local namespace
-	// will appear below mt1.
-	r, err := rt.New(veyron2.NamespaceRoots([]string{naming.JoinAddressName(estr, mt1Prefix)}))
-	if err != nil {
-		boom(t, "Failed to create client runtime: %s", err)
-	}
-	mt := r.Namespace()
-
-	ctx := r.NewContext()
-
-	// Create a DAG of mount table servers using relative addresses.
-	ttl := time.Duration(100) * time.Second
-	// Mount using a relative name starting with //.  This means don't walk out of the
-	// namespace's root mount table even if there is already something mounted at mt2.
-	mt2Name := naming.JoinAddressName(estr, mt2Prefix)
-	if err := mt.Mount(ctx, "//mt2", mt2Name, ttl); err != nil {
-		boom(t, "Failed to Mount //mt2: %s", err)
-	}
-	// Mount using the relative name not starting with //.  This means walk through mt3
-	// if it already exists and mount at its root.  However, since it doesn't exist, this is the
-	// same as if we'd mounted at //mt3.
-	//
-	// NB: if we mount two replica mount table servers at the same place in the namespace,
-	// we MUST use the // form or it will try to mount the second inside the first rather
-	// than at the same place as the first.
-	mt3Name := naming.JoinAddressName(estr, mt3Prefix)
-	if err := mt.Mount(ctx, "mt3", mt3Name, ttl); err != nil {
-		boom(t, "Failed to Mount mt3: %s", err)
-	}
-
-	mt1MT := naming.MakeTerminal(naming.JoinAddressName(estr, mt1Prefix))
-	mt2MT := naming.MakeTerminal(naming.JoinAddressName(estr, naming.Join(mt1Prefix, mt2Prefix)))
-	mt3MT := naming.MakeTerminal(naming.JoinAddressName(estr, naming.Join(mt1Prefix, mt3Prefix)))
-
-	// After the mounts above we have MountTables at /<estr>/mt1{//mt2,//mt3},
-	// with server addresses as per below.
-	testResolveToMountTable(t, ctx, mt, "", mt1MT)
-	testResolveToMountTable(t, ctx, mt, "mt2", mt2MT)
-	testResolveToMountTable(t, ctx, mt, "mt3", mt3MT)
-	testResolveToMountTable(t, ctx, mt, "//mt3", naming.JoinAddressName(estr, "//mt1//mt3"))
-
-	// We can resolve to the MountTables using rooted, terminal names
-	// as follows, both mt1 and mt1/{mt2,mt3} are served by the
-	// top-level MountTable
-	testResolve(t, ctx, mt, naming.JoinAddressName(estr, "//mt1"), mt1MT)
-	testResolve(t, ctx, mt, naming.JoinAddressName(estr, "//mt1/mt2"), mt2MT)
-	testResolve(t, ctx, mt, naming.JoinAddressName(estr, "//mt1/mt3"), mt3MT)
-
-	// returns [mt2, mt3]
-	vlog.Infof("GLOB: %s", doGlob(t, ctx, mt, "*"))
-
-	// Perform two mounts that have to actually walk through other mount tables.
-	if err := mt.Mount(ctx, "mt2/mt4", naming.JoinAddressName(estr, mt4Prefix), ttl); err != nil {
-		boom(t, "Failed to Mount mt2/mt4: %s", err)
-	}
-	if err := mt.Mount(ctx, "mt3/mt4", naming.JoinAddressName(estr, mt4Prefix), ttl); err != nil {
-		boom(t, "Failed to Mount mt3/mt4: %s", err)
-	}
-
-	// After the mounts above we now have /<estr>{/mt1/mt2/mt4,/mt1/mt3/mt4}.
-	testResolveToMountTable(t, ctx, mt, "mt2/mt4", naming.JoinAddressName(estr, "//mt2/mt4"))
-	testResolveToMountTable(t, ctx, mt, "mt3/mt4", naming.JoinAddressName(estr, "//mt3/mt4"))
-
-	testResolve(t, ctx, mt, naming.JoinAddressName(estr, "//mt1/mt2/mt4"), naming.JoinAddressName(estr, "//mt1/mt2/mt4"))
-
-	// Perform a mount that uses a global name as the mount point rather than
-	// one relative to our namespace's root.
-	global := naming.JoinAddressName(estr, "mt3/mt4/mt5")
-	if err := mt.Mount(ctx, global, naming.JoinAddressName(estr, mt5Prefix), ttl); err != nil {
-		boom(t, "Failed to Mount %s: %s", global, err)
-	}
-
-	// This mounts the service OA (ep/joke1) as joke1.
-	if err := mt.Mount(ctx, "joke1", naming.JoinAddressName(estr, "//joke1"), ttl); err != nil {
-		boom(t, "Failed to Mount joke1: %s", err)
-	}
-	// This mounts the raw server endpoint as joke2 -- like Publish would.
-	if err := mt.Mount(ctx, "joke2", naming.JoinAddressName(estr, "")+"//", ttl); err != nil {
-		boom(t, "Failed to Mount joke2: %s", err)
-	}
-	// This mounts the raw server endpoint as joke3 in mt3 -- like Publish would.
-	if err := mt.Mount(ctx, "mt3/joke3", naming.JoinAddressName(estr, "")+"//", ttl); err != nil {
-		boom(t, "Failed to Mount joke3: %s", err)
-	}
-
-	// After the mounts above we have:
-	// /<estr>/mt3/mt4/mt5 - the global mount above
-	// /<estr>/mt1/{joke1,joke2,mt3/joker3}
-
-	// Now try resolving inside the namespace.   This guarantees both that the mounts did
-	// what we expected AND that we can actually resolve the results.
-
-	// Get back an error since this will walk through mt5 to its root.
-	_, err = mt.Resolve(ctx, "mt3/mt4/mt5")
-	if err == nil {
-		boom(t, "Should have failed to mt3/mt4/mt5")
-	}
-
-	// Resolving m3/mt4/mt5 to a MountTable using the local namepsace gives
-	// us /<estr>//mt4/mt5.
-	testResolveToMountTable(t, ctx, mt, "mt3/mt4/mt5", naming.JoinAddressName(estr, "//mt4/mt5"))
-	testResolveToMountTable(t, ctx, mt, "mt3/mt4//mt5", naming.JoinAddressName(estr, "//mt4//mt5"))
-
-	// But looking up mt4/mt5 in the local namespace will give us
-	// /<estr>//mt1/mt4/mt5 since the local namespace has mt1 as its root!
-	testResolveToMountTable(t, ctx, mt, "mt4/mt5", naming.JoinAddressName(estr, "//mt1/mt4/mt5"))
-
-	// Looking mt3//mt4/mt5 will return the MountTable that serves //mt4/mt5.
-	testResolveToMountTable(t, ctx, mt, "mt3//mt4/mt5", naming.JoinAddressName(estr, "//mt3//mt4/mt5"))
-	// And the MountTable that serves //mt4/mt5 is /<epstr>//mt1/mt4/mt5
-	testResolveToMountTable(t, ctx, mt, "//mt4/mt5", naming.JoinAddressName(estr, "//mt1//mt4/mt5"))
-
-	vlog.Infof("\n-------------------------------------------------")
-	jokeTests := []struct {
-		name, resolved, resolvedToMT string
-	}{
-		{"joke1", naming.JoinAddressName(estr, "//joke1"), naming.JoinAddressName(estr, "//mt1/joke1")},
-		{"joke2", naming.JoinAddressName(estr, "") + "//", naming.JoinAddressName(estr, "//mt1/joke2")},
-		{"mt3/joke3", naming.JoinAddressName(estr, "") + "//", naming.JoinAddressName(estr, "//mt3/joke3")},
-	}
-	for _, test := range jokeTests {
-
-		servers, err := mt.Resolve(ctx, test.name)
-		if err != nil {
-			boom(t, "Failed to Resolve %s: %s", test.name, err)
-		}
-		if len(servers) != 1 || servers[0] != test.resolved {
-			boom(t, "Resolve %s returned wrong servers: %v, expected: %s", test.name, servers, test.resolved)
-		}
-
-		servers, err = mt.ResolveToMountTable(ctx, test.name)
-		if err != nil {
-			boom(t, "Failed to ResolveToMountTable %s: %s", test.name, err)
-		}
-		if len(servers) != 1 || servers[0] != test.resolvedToMT {
-			boom(t, "ResolveToMountTable %s returned wrong servers: %v, expected: %s", test.name, servers, test.resolvedToMT)
-		}
-	}
-
-	knockKnock(t, r, "joke1")
-	knockKnock(t, r, "joke2/joke2")
-	knockKnock(t, r, "mt3/joke3/joke3")
-
-	// Try various globs.
-	globTests := []struct {
-		pattern  string
-		expected []string
-	}{
-		{"*", []string{"mt2", "mt3", "joke1", "joke2"}},
-
-		{"*/...", []string{"mt2", "mt3", "mt2/mt4", "mt3/mt4", "mt2/mt4/mt5", "mt3/mt4/mt5", "joke1", "joke2", "mt3/joke3"}},
-		{"*/m?4/*5", []string{"mt2/mt4/mt5", "mt3/mt4/mt5"}},
-		{"*2*/*/*5", []string{"mt2/mt4/mt5"}},
-		{"mt2/*/*5", []string{"mt2/mt4/mt5"}},
-		{"mt2/mt4/*5", []string{"mt2/mt4/mt5"}},
-	}
-	for _, test := range globTests {
-		out := doGlob(t, ctx, mt, test.pattern)
-		checkMatch(t, test.pattern, test.expected, out)
-	}
-
-}
diff --git a/runtimes/google/naming/namespace/mount.go b/runtimes/google/naming/namespace/mount.go
index 721ef85..78eeda3 100644
--- a/runtimes/google/naming/namespace/mount.go
+++ b/runtimes/google/naming/namespace/mount.go
@@ -5,6 +5,7 @@
 
 	"veyron2/context"
 	"veyron2/ipc"
+	"veyron2/vlog"
 )
 
 // mountIntoMountTable mounts a single server into a single mount table.
@@ -52,6 +53,7 @@
 			finalerr = err
 		}
 	}
+	vlog.VI(1).Infof("Mount(%s, %s) -> %v", name, server, finalerr)
 	return finalerr
 }
 
diff --git a/runtimes/google/naming/namespace/namespace.go b/runtimes/google/naming/namespace/namespace.go
index bc64e1f..16b4fdd 100644
--- a/runtimes/google/naming/namespace/namespace.go
+++ b/runtimes/google/naming/namespace/namespace.go
@@ -41,7 +41,7 @@
 }
 
 // SetRoots implements naming.MountTable.SetRoots
-func (ns *namespace) SetRoots(roots []string) error {
+func (ns *namespace) SetRoots(roots ...string) error {
 	if !rooted(roots) {
 		return badRoots(roots)
 	}
@@ -52,6 +52,17 @@
 	return nil
 }
 
+// Roots implements naming.MountTable.Roots
+func (ns *namespace) Roots() []string {
+	ns.RLock()
+	defer ns.RUnlock()
+	roots := make([]string, len(ns.roots))
+	for i, r := range ns.roots {
+		roots[i] = r
+	}
+	return roots
+}
+
 // rootName 'roots' a name: if name is not a rooted name, it prepends the root
 // mounttable's OA.
 func (ns *namespace) rootName(name string) []string {
diff --git a/runtimes/google/naming/namespace/resolve.go b/runtimes/google/naming/namespace/resolve.go
index 92fc6f0..3043a31 100644
--- a/runtimes/google/naming/namespace/resolve.go
+++ b/runtimes/google/naming/namespace/resolve.go
@@ -2,6 +2,7 @@
 
 import (
 	"errors"
+	"runtime"
 
 	"veyron2/context"
 	"veyron2/ipc"
@@ -72,60 +73,77 @@
 	return
 }
 
-// Resolve implements veyron2/naming.MountTable.
+// Resolve implements veyron2/naming.Namespace.
 func (ns *namespace) Resolve(ctx context.T, name string) ([]string, error) {
-	vlog.VI(2).Infof("Resolve %s", name)
 	names := ns.rootName(name)
+	if vlog.V(2) {
+		_, file, line, _ := runtime.Caller(1)
+		vlog.Infof("Resolve(%s) called from %s:%d", name, file, line)
+		vlog.Infof("Resolve(%s) -> rootNames %s", name, names)
+	}
 	if len(names) == 0 {
 		return nil, naming.ErrNoMountTable
 	}
 	// Iterate walking through mount table servers.
 	for remaining := maxDepth; remaining > 0; remaining-- {
-		vlog.VI(2).Infof("Resolve loop %s", names)
+		vlog.VI(2).Infof("Resolve(%s) loop %s", name, names)
 		if terminal(names) {
+			vlog.VI(1).Infof("Resolve(%s) -> %s", name, names)
 			return names, nil
 		}
 		var err error
 		curr := names
 		if names, err = resolveAgainstMountTable(ctx, ns.rt.Client(), names); err != nil {
-
 			// If the name could not be found in the mount table, return an error.
 			if verror.Equal(naming.ErrNoSuchNameRoot, err) {
 				err = naming.ErrNoSuchName
 			}
 			if verror.Equal(naming.ErrNoSuchName, err) {
+				vlog.VI(1).Infof("Resolve(%s) -> (NoSuchName: %v)", name, curr)
 				return nil, err
 			}
 			// Any other failure (server not found, no ResolveStep
 			// method, etc.) are a sign that iterative resolution can
 			// stop.
-			return makeTerminal(curr), nil
+			t := makeTerminal(curr)
+			vlog.VI(1).Infof("Resolve(%s) -> %s", name, t)
+			return t, nil
 		}
 	}
 	return nil, naming.ErrResolutionDepthExceeded
 }
 
-// ResolveToMountTable implements veyron2/naming.MountTable.
+// ResolveToMountTable implements veyron2/naming.Namespace.
 func (ns *namespace) ResolveToMountTable(ctx context.T, name string) ([]string, error) {
 	names := ns.rootName(name)
-	vlog.VI(2).Infof("ResolveToMountTable %s -> rootNames %s", name, names)
+	if vlog.V(2) {
+		_, file, line, _ := runtime.Caller(1)
+		vlog.Infof("ResolveToMountTable(%s) called from %s:%d", name, file, line)
+		vlog.Infof("ResolveToMountTable(%s) -> rootNames %s", name, names)
+	}
 	if len(names) == 0 {
 		return nil, naming.ErrNoMountTable
 	}
 	last := names
 	for remaining := maxDepth; remaining > 0; remaining-- {
-		vlog.VI(2).Infof("ResolveToMountTable loop %s", names)
+		vlog.VI(2).Infof("ResolveToMountTable(%s) loop %s", name, names)
 		var err error
 		curr := names
 		if terminal(curr) {
-			return makeTerminal(last), nil
+			t := makeTerminal(last)
+			vlog.VI(1).Infof("ResolveToMountTable(%s) -> %s", name, t)
+			return t, nil
 		}
 		if names, err = resolveAgainstMountTable(ctx, ns.rt.Client(), names); err != nil {
 			if verror.Equal(naming.ErrNoSuchNameRoot, err) {
-				return makeTerminal(last), nil
+				t := makeTerminal(last)
+				vlog.VI(1).Infof("ResolveToMountTable(%s) -> %s (NoSuchRoot: %v)", name, t, curr)
+				return t, nil
 			}
 			if verror.Equal(naming.ErrNoSuchName, err) {
-				return makeTerminal(curr), nil
+				t := makeTerminal(curr)
+				vlog.VI(1).Infof("ResolveToMountTable(%s) -> %s (NoSuchName: %v)", name, t, curr)
+				return t, nil
 			}
 			// Lots of reasons why another error can happen.  We are trying
 			// to single out "this isn't a mount table".
@@ -133,11 +151,14 @@
 			// that means "we are up but don't implement what you are
 			// asking for".
 			if notAnMT(err) {
-				return makeTerminal(last), nil
+				t := makeTerminal(last)
+				vlog.VI(1).Infof("ResolveToMountTable(%s) -> %s", name, t)
+				return t, nil
 			}
 			// TODO(caprita): If the server is unreachable for
 			// example, we may still want to return its parent
 			// mounttable rather than an error.
+			vlog.VI(1).Infof("ResolveToMountTable(%s) -> %v", name, err)
 			return nil, err
 		}
 
@@ -184,7 +205,7 @@
 // selecting the right branch (or should we return a representative of all
 // branches?).
 
-// Unesolve implements veyron2/naming.MountTable.
+// Unesolve implements veyron2/naming.Namespace.
 func (ns *namespace) Unresolve(ctx context.T, name string) ([]string, error) {
 	vlog.VI(2).Infof("Unresolve %s", name)
 	names, err := ns.Resolve(ctx, name)
diff --git a/runtimes/google/rt/mgmt.go b/runtimes/google/rt/mgmt.go
index ae53bb4..ccfebd7 100644
--- a/runtimes/google/rt/mgmt.go
+++ b/runtimes/google/rt/mgmt.go
@@ -52,16 +52,15 @@
 	if m.server, err = rt.NewServer(); err != nil {
 		return err
 	}
-	const suffix = ""
-	if err := m.server.Register(suffix, ipc.SoloDispatcher(appcycle.NewServerAppCycle(m), vflag.NewAuthorizerOrDie())); err != nil {
-		return err
-	}
 	// TODO(caprita): We should pick the address to listen on from config.
 	var ep naming.Endpoint
 	if ep, err = m.server.Listen("tcp", "127.0.0.1:0"); err != nil {
 		return err
 	}
-	return m.callbackToParent(parentName, naming.JoinAddressName(ep.String(), suffix))
+	if err := m.server.Serve("", ipc.SoloDispatcher(appcycle.NewServerAppCycle(m), vflag.NewAuthorizerOrDie())); err != nil {
+		return err
+	}
+	return m.callbackToParent(parentName, naming.JoinAddressName(ep.String(), ""))
 }
 
 func (m *mgmtImpl) callbackToParent(parentName, myName string) error {
diff --git a/runtimes/google/rt/mgmt_test.go b/runtimes/google/rt/mgmt_test.go
index 0c38c3c..e3dfdf6 100644
--- a/runtimes/google/rt/mgmt_test.go
+++ b/runtimes/google/rt/mgmt_test.go
@@ -245,16 +245,16 @@
 	if err != nil {
 		t.Fatalf("Got error: %v", err)
 	}
-	const suffix = ""
 	ch := make(chan string)
-	if err := server.Register(suffix, ipc.SoloDispatcher(node.NewServerConfig(&configServer{ch}), vflag.NewAuthorizerOrDie())); err != nil {
-		t.Fatalf("Got error: %v", err)
-	}
+
 	var ep naming.Endpoint
 	if ep, err = server.Listen("tcp", "127.0.0.1:0"); err != nil {
 		t.Fatalf("Got error: %v", err)
 	}
-	return server, naming.JoinAddressName(ep.String(), suffix), ch
+	if err := server.Serve("", ipc.SoloDispatcher(node.NewServerConfig(&configServer{ch}), vflag.NewAuthorizerOrDie())); err != nil {
+		t.Fatalf("Got error: %v", err)
+	}
+	return server, naming.JoinAddressName(ep.String(), ""), ch
 
 }
 
diff --git a/runtimes/google/vsync/vsyncd/main.go b/runtimes/google/vsync/vsyncd/main.go
index a2ca5a9..506c49d 100644
--- a/runtimes/google/vsync/vsyncd/main.go
+++ b/runtimes/google/vsync/vsyncd/main.go
@@ -41,9 +41,7 @@
 	// Register the "sync" prefix with the sync dispatcher.
 	syncd := vsync.NewSyncd(*peerEndpoints, *peerDeviceIDs, *devid, *storePath, *vstoreEndpoint, *syncTick)
 	serverSync := vsync.NewServerSync(syncd)
-	if err := s.Register("sync", ipc.SoloDispatcher(serverSync, nil)); err != nil {
-		vlog.Fatalf("syncd:: error registering service: err %v", err)
-	}
+	dispatcher := ipc.SoloDispatcher(serverSync, nil)
 
 	// Create an endpoint and begin listening.
 	if endpoint, err := s.Listen("tcp", *address); err == nil {
@@ -54,7 +52,7 @@
 
 	// Publish the vsync service. This will register it in the mount table and maintain the
 	// registration while the program runs.
-	if err := s.Publish("sync"); err != nil {
+	if err := s.Serve("sync", dispatcher); err != nil {
 		vlog.Fatalf("syncd: error publishing service: err %v", err)
 	}
 
diff --git a/services/mgmt/application/applicationd/main.go b/services/mgmt/application/applicationd/main.go
index f5bf624..d5e0a33 100644
--- a/services/mgmt/application/applicationd/main.go
+++ b/services/mgmt/application/applicationd/main.go
@@ -34,16 +34,12 @@
 	if err != nil {
 		vlog.Fatalf("NewDispatcher() failed: %v", err)
 	}
-	suffix := ""
-	if err := server.Register(suffix, dispatcher); err != nil {
-		vlog.Fatalf("Register(%v, %v) failed: %v", suffix, dispatcher, err)
-	}
 	endpoint, err := server.Listen(protocol, address)
 	if err != nil {
 		vlog.Fatalf("Listen(%v, %v) failed: %v", protocol, address, err)
 	}
-	if err := server.Publish(name); err != nil {
-		vlog.Fatalf("Publish(%v) failed: %v", name, err)
+	if err := server.Serve(name, dispatcher); err != nil {
+		vlog.Fatalf("Serve(%v) failed: %v", name, err)
 	}
 	vlog.VI(0).Infof("Application manager published at %v/%v", endpoint, name)
 
diff --git a/services/mgmt/application/impl/impl_test.go b/services/mgmt/application/impl/impl_test.go
index cee0cdb..76a0fd6 100644
--- a/services/mgmt/application/impl/impl_test.go
+++ b/services/mgmt/application/impl/impl_test.go
@@ -24,24 +24,30 @@
 	if err != nil {
 		t.Fatalf("NewServer() failed: %v", err)
 	}
+	defer server.Stop()
 
 	// Setup and start a store server.
-	name, cleanup := testutil.NewStore(t, server, runtime.Identity().PublicID())
+	store, cleanup := testutil.NewStore(t, server, runtime.Identity().PublicID())
 	defer cleanup()
 
-	dispatcher, err := NewDispatcher(name, nil)
+	server, err = runtime.NewServer()
+	if err != nil {
+		t.Fatalf("NewServer() failed: %v", err)
+	}
+
+	dispatcher, err := NewDispatcher(store, nil)
 	if err != nil {
 		t.Fatalf("NewDispatcher() failed: %v", err)
 	}
-	suffix := ""
-	if err := server.Register(suffix, dispatcher); err != nil {
-		t.Fatalf("Register(%v, %v) failed: %v", suffix, dispatcher, err)
-	}
+
 	protocol, hostname := "tcp", "localhost:0"
 	endpoint, err := server.Listen(protocol, hostname)
 	if err != nil {
 		t.Fatalf("Listen(%v, %v) failed: %v", protocol, hostname, err)
 	}
+	if err := server.Serve("", dispatcher); err != nil {
+		t.Fatalf("Serve(%v) failed: %v", dispatcher, err)
+	}
 
 	// Create client stubs for talking to the server.
 	stub, err := repository.BindApplication(naming.JoinAddressName(endpoint.String(), "//search"))
diff --git a/services/mgmt/node/impl/impl_test.go b/services/mgmt/node/impl/impl_test.go
index 5a2d08b..361f399 100644
--- a/services/mgmt/node/impl/impl_test.go
+++ b/services/mgmt/node/impl/impl_test.go
@@ -262,10 +262,7 @@
 	if err != nil {
 		vlog.Fatalf("NewServer() failed: %v", err)
 	}
-	suffix, dispatcher := "", ipc.SoloDispatcher(repository.NewServerApplication(&arInvoker{}), nil)
-	if err := server.Register(suffix, dispatcher); err != nil {
-		vlog.Fatalf("Register(%v, %v) failed: %v", suffix, dispatcher, err)
-	}
+	dispatcher := ipc.SoloDispatcher(repository.NewServerApplication(&arInvoker{}), nil)
 	protocol, hostname := "tcp", "localhost:0"
 	endpoint, err := server.Listen(protocol, hostname)
 	if err != nil {
@@ -273,8 +270,8 @@
 	}
 	vlog.VI(1).Infof("Application repository running at endpoint: %s", endpoint)
 	name := "ar"
-	if err := server.Publish(name); err != nil {
-		vlog.Fatalf("Publish(%v) failed: %v", name, err)
+	if err := server.Serve(name, dispatcher); err != nil {
+		vlog.Fatalf("Serve(%v) failed: %v", name, err)
 	}
 	return name, func() {
 		if err := server.Stop(); err != nil {
@@ -288,10 +285,7 @@
 	if err != nil {
 		vlog.Fatalf("NewServer() failed: %v", err)
 	}
-	suffix, dispatcher := "", ipc.SoloDispatcher(repository.NewServerBinary(&crInvoker{}), nil)
-	if err := server.Register(suffix, dispatcher); err != nil {
-		vlog.Fatalf("Register(%v, %v) failed: %v", suffix, dispatcher, err)
-	}
+	dispatcher := ipc.SoloDispatcher(repository.NewServerContent(&crInvoker{}), nil)
 	protocol, hostname := "tcp", "localhost:0"
 	endpoint, err := server.Listen(protocol, hostname)
 	if err != nil {
@@ -299,8 +293,8 @@
 	}
 	vlog.VI(1).Infof("Binary repository running at endpoint: %s", endpoint)
 	name := "cr"
-	if err := server.Publish(name); err != nil {
-		vlog.Fatalf("Publish(%v) failed: %v", name, err)
+	if err := server.Serve(name, dispatcher); err != nil {
+		vlog.Fatalf("Serve(%v) failed: %v", name, err)
 	}
 	return name, func() {
 		if err := server.Stop(); err != nil {
@@ -318,16 +312,15 @@
 	if err != nil {
 		t.Fatalf("NewMountTable() failed: %v", err)
 	}
-	suffix := "mt"
-	if err := server.Register(suffix, dispatcher); err != nil {
-		t.Fatalf("Register(%v, %v) failed: %v", suffix, dispatcher, err)
-	}
 	protocol, hostname := "tcp", "localhost:0"
 	endpoint, err := server.Listen(protocol, hostname)
 	if err != nil {
 		t.Fatalf("Listen(%v, %v) failed: %v", protocol, hostname, err)
 	}
-	name := naming.JoinAddressName(endpoint.String(), suffix)
+	if err := server.Serve("", dispatcher); err != nil {
+		t.Fatalf("Serve(%v) failed: %v", dispatcher, err)
+	}
+	name := naming.JoinAddressName(endpoint.String(), "")
 	vlog.VI(1).Infof("Mount table name: %v", name)
 	return name, func() {
 		if err := server.Stop(); err != nil {
@@ -346,18 +339,15 @@
 	if err != nil {
 		vlog.Fatalf("Listen(%v, %v) failed: %v", protocol, hostname, err)
 	}
-	suffix, envelope := "", &application.Envelope{}
-	name := naming.MakeTerminal(naming.JoinAddressName(endpoint.String(), suffix))
+	envelope := &application.Envelope{}
+	name := naming.MakeTerminal(naming.JoinAddressName(endpoint.String(), ""))
 	vlog.VI(0).Infof("Node manager name: %v", name)
 	// TODO(jsimsa): Replace <PreviousEnv> with a command-line flag when
 	// command-line flags in tests are supported.
 	dispatcher := impl.NewDispatcher(nil, envelope, name, os.Getenv(impl.PreviousEnv))
-	if err := server.Register(suffix, dispatcher); err != nil {
-		vlog.Fatalf("Register(%v, %v) failed: %v", suffix, dispatcher, err)
-	}
 	publishAs := "nm"
-	if err := server.Publish(publishAs); err != nil {
-		vlog.Fatalf("Publish(%v) failed: %v", publishAs, err)
+	if err := server.Serve(publishAs, dispatcher); err != nil {
+		vlog.Fatalf("Serve(%v) failed: %v", publishAs, err)
 	}
 	fmt.Printf("ready\n")
 	return name, func() {
@@ -408,7 +398,7 @@
 	ns := runtime.Namespace()
 	// The local, client-side Namespace is now relative to the
 	// MountTable server started above.
-	ns.SetRoots([]string{mtName})
+	ns.SetRoots(mtName)
 	// Spawn a node manager with an identity blessed by the MountTable's
 	// identity under the name "test", and obtain its address.
 	//
diff --git a/services/mgmt/node/noded/main.go b/services/mgmt/node/noded/main.go
index ec9762b..af7c5d2 100644
--- a/services/mgmt/node/noded/main.go
+++ b/services/mgmt/node/noded/main.go
@@ -44,13 +44,8 @@
 	// TODO(jsimsa): Replace <PreviousEnv> with a command-line flag when
 	// command-line flags are supported in tests.
 	dispatcher := impl.NewDispatcher(vflag.NewAuthorizerOrDie(), envelope, name, os.Getenv(impl.PreviousEnv))
-	if err := server.Register(suffix, dispatcher); err != nil {
-		vlog.Fatalf("Register(%v, %v) failed: %v", suffix, dispatcher, err)
-	}
-	if len(publishAs) > 0 {
-		if err := server.Publish(publishAs); err != nil {
-			vlog.Fatalf("Publish(%v) failed: %v", publishAs, err)
-		}
+	if err := server.Serve(publishAs, dispatcher); err != nil {
+		vlog.Fatalf("Serve(%v) failed: %v", publishAs, err)
 	}
 	handle, _ := exec.GetChildHandle()
 	if handle != nil {
diff --git a/services/mgmt/profile/impl/impl_test.go b/services/mgmt/profile/impl/impl_test.go
index 777444c..6822260 100644
--- a/services/mgmt/profile/impl/impl_test.go
+++ b/services/mgmt/profile/impl/impl_test.go
@@ -35,29 +35,31 @@
 	if err != nil {
 		t.Fatalf("NewServer() failed: %v", err)
 	}
+	defer server.Stop()
 
 	// Setup and start a store server.
 	mountPoint, cleanup := testutil.NewStore(t, server, runtime.Identity().PublicID())
 	defer cleanup()
 
+	// Setup and start the profile server.
+	server, err = runtime.NewServer()
+	if err != nil {
+		t.Fatalf("NewServer() failed: %v", err)
+	}
+
 	dispatcher, err := NewDispatcher(mountPoint, nil)
 	if err != nil {
 		t.Fatalf("NewDispatcher() failed: %v", err)
 	}
-	suffix := ""
-	if err := server.Register(suffix, dispatcher); err != nil {
-		t.Fatalf("Register(%v, %v) failed: %v", suffix, dispatcher, err)
-	}
 	protocol, hostname := "tcp", "localhost:0"
 	endpoint, err := server.Listen(protocol, hostname)
 	if err != nil {
 		t.Fatalf("Listen(%v, %v) failed: %v", protocol, hostname, err)
 	}
-	name := ""
-	if err := server.Publish(name); err != nil {
-		t.Fatalf("Publish(%v) failed: %v", name, err)
+	if err := server.Serve("", dispatcher); err != nil {
+		t.Fatalf("Serve failed: %v", err)
 	}
-	t.Logf("Profile repository published at %v/%v", endpoint, name)
+	t.Logf("Profile repository at %v", endpoint)
 
 	// Create client stubs for talking to the server.
 	stub, err := repository.BindProfile(naming.JoinAddressName(endpoint.String(), "//linux/base"))
diff --git a/services/mgmt/profile/profiled/main.go b/services/mgmt/profile/profiled/main.go
index 51ca649..cc33f62 100644
--- a/services/mgmt/profile/profiled/main.go
+++ b/services/mgmt/profile/profiled/main.go
@@ -33,16 +33,13 @@
 	if err != nil {
 		vlog.Fatalf("NewDispatcher() failed: %v", err)
 	}
-	suffix := ""
-	if err := server.Register(suffix, dispatcher); err != nil {
-		vlog.Fatalf("Register(%v, %v) failed: %v", suffix, dispatcher, err)
-	}
+
 	endpoint, err := server.Listen(protocol, address)
 	if err != nil {
 		vlog.Fatalf("Listen(%v, %v) failed: %v", protocol, address, err)
 	}
-	if err := server.Publish(name); err != nil {
-		vlog.Fatalf("Publish(%v) failed: %v", name, err)
+	if err := server.Serve(name, dispatcher); err != nil {
+		vlog.Fatalf("Serve(%v) failed: %v", name, err)
 	}
 	vlog.VI(0).Infof("Profile manager published at %v/%v", endpoint, name)
 
diff --git a/services/mgmt/root/rootd/main.go b/services/mgmt/root/rootd/main.go
index d28b6f4..ae4b33a 100644
--- a/services/mgmt/root/rootd/main.go
+++ b/services/mgmt/root/rootd/main.go
@@ -17,11 +17,7 @@
 		return
 	}
 	defer server.Stop()
-	suffix, dispatcher := "", impl.NewDispatcher()
-	if err := server.Register(suffix, dispatcher); err != nil {
-		vlog.Errorf("Register(%v, %v) failed: %v", suffix, dispatcher, err)
-		return
-	}
+	dispatcher := impl.NewDispatcher()
 	protocol, hostname := "tcp", "localhost:0"
 	ep, err := server.Listen(protocol, hostname)
 	if err != nil {
@@ -30,8 +26,8 @@
 	}
 	vlog.VI(0).Infof("Listening on %v", ep)
 	name := ""
-	if err := server.Publish(name); err != nil {
-		vlog.Errorf("Publish(%v) failed: %v", name, err)
+	if err := server.Serve(name, dispatcher); err != nil {
+		vlog.Errorf("Serve(%v) failed: %v", name, err)
 		return
 	}
 
diff --git a/services/mounttable/lib/mounttable_test.go b/services/mounttable/lib/mounttable_test.go
index f8744bc..e961bc5 100644
--- a/services/mounttable/lib/mounttable_test.go
+++ b/services/mounttable/lib/mounttable_test.go
@@ -102,10 +102,14 @@
 	return nil, errors.New("Glob is not implemented in this MountTable")
 }
 
-func (s stupidNS) SetRoots([]string) error {
+func (s stupidNS) SetRoots(...string) error {
 	return nil
 }
 
+func (s stupidNS) Roots() []string {
+	return []string{}
+}
+
 func doMount(t *testing.T, name, service string, shouldSucceed bool, id ipc.ClientOpt) {
 	mtpt, err := mounttable.BindMountTable(name, quuxClient(id))
 	if err != nil {
@@ -164,90 +168,108 @@
 	}
 }
 
-func newServer(acl string, t *testing.T) (ipc.Server, string) {
+func newMT(t *testing.T, acl string) (ipc.Server, string) {
 	r := rt.Init()
-	server, err := r.NewServer()
+	server, err := r.NewServer(veyron2.ServesMountTableOpt(true))
 	if err != nil {
 		boom(t, "r.NewServer: %s", err)
 	}
-
 	// Add mount table service.
 	mt, err := NewMountTable(acl)
 	if err != nil {
 		boom(t, "NewMountTable: %v", err)
 	}
-	if err := server.Register("mounttable", mt); err != nil {
-		boom(t, "Failed to register mount table: %s", err)
-	}
-
 	// Start serving on a loopback address.
 	e, err := server.Listen("tcp", "127.0.0.1:0")
 	if err != nil {
 		boom(t, "Failed to Listen mount table: %s", err)
 	}
+	if err := server.Serve("", mt); err != nil {
+		boom(t, "Failed to register mock collection: %s", err)
+	}
+	estr := e.String()
+	t.Logf("endpoint %s", estr)
+	return server, estr
+}
+
+func newCollection(t *testing.T, acl string) (ipc.Server, string) {
+	r := rt.Init()
+	server, err := r.NewServer()
+	if err != nil {
+		boom(t, "r.NewServer: %s", err)
+	}
+	// Start serving on a loopback address.
+	e, err := server.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		boom(t, "Failed to Listen mount table: %s", err)
+	}
+	// Add a collection service.  This is just a service we can mount
+	// and test against.
+	cPrefix := "collection"
+	if err := server.Serve(cPrefix, newCollectionServer()); err != nil {
+		boom(t, "Failed to register mock collection: %s", err)
+	}
 	estr := e.String()
 	t.Logf("endpoint %s", estr)
 	return server, estr
 }
 
 func TestMountTable(t *testing.T) {
-	server, estr := newServer("testdata/test.acl", t)
-	defer server.Stop()
-	// Add a collection service.  This is just a service we can mount
-	// and test against.
-	cPrefix := "collection"
-	if err := server.Register(cPrefix, newCollectionServer()); err != nil {
-		boom(t, "Failed to register mock collection: %s", err)
-	}
+	mt, mtAddr := newMT(t, "testdata/test.acl")
+	defer mt.Stop()
+	collection, collectionAddr := newCollection(t, "testdata/test.acl")
+	defer collection.Stop()
+
+	collectionName := naming.JoinAddressName(collectionAddr, "collection")
 
 	// Mount the collection server into the mount table.
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/stuff"), naming.JoinAddressName(estr, "collection"), true, rootID)
+	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable/stuff"), collectionName, true, rootID)
 
 	// Create a few objects and make sure we can read them.
-	create(t, naming.JoinAddressName(estr, "mounttable/stuff/the/rain"), "the rain")
-	create(t, naming.JoinAddressName(estr, "mounttable/stuff/in/spain"), "in spain")
-	create(t, naming.JoinAddressName(estr, "mounttable/stuff/falls"), "falls mainly on the plain")
-	checkContents(t, naming.JoinAddressName(estr, "mounttable/stuff/the/rain"), "the rain", true, rootID)
-	checkContents(t, naming.JoinAddressName(estr, "mounttable/stuff/in/spain"), "in spain", true, rootID)
-	checkContents(t, naming.JoinAddressName(estr, "mounttable/stuff/falls"), "falls mainly on the plain", true, rootID)
-	checkContents(t, naming.JoinAddressName(estr, "mounttable//stuff/falls"), "falls mainly on the plain", false, rootID)
-	checkContents(t, naming.JoinAddressName(estr, "mounttable/stuff/nonexistant"), "falls mainly on the plain", false, rootID)
-	checkContents(t, naming.JoinAddressName(estr, "mounttable/stuff/the/rain"), "the rain", true, bobID)
-	checkContents(t, naming.JoinAddressName(estr, "mounttable/stuff/the/rain"), "the rain", false, aliceID)
+	create(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/the/rain"), "the rain")
+	create(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/in/spain"), "in spain")
+	create(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/falls"), "falls mainly on the plain")
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/the/rain"), "the rain", true, rootID)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/in/spain"), "in spain", true, rootID)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/falls"), "falls mainly on the plain", true, rootID)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable//stuff/falls"), "falls mainly on the plain", false, rootID)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/nonexistant"), "falls mainly on the plain", false, rootID)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/the/rain"), "the rain", true, bobID)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/the/rain"), "the rain", false, aliceID)
 
 	// Test multiple mounts.
-	doMount(t, naming.JoinAddressName(estr, "//mounttable//a/b"), naming.JoinAddressName(estr, "collection"), true, rootID)
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/x/y"), naming.JoinAddressName(estr, "collection"), true, rootID)
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/alpha//beta"), naming.JoinAddressName(estr, "collection"), true, rootID)
-	checkContents(t, naming.JoinAddressName(estr, "mounttable/stuff/falls"), "falls mainly on the plain", true, rootID)
-	checkContents(t, naming.JoinAddressName(estr, "mounttable/a/b/falls"), "falls mainly on the plain", true, rootID)
-	checkContents(t, naming.JoinAddressName(estr, "mounttable/x/y/falls"), "falls mainly on the plain", true, rootID)
-	checkContents(t, naming.JoinAddressName(estr, "mounttable/alpha/beta/falls"), "falls mainly on the plain", true, rootID)
-	checkContents(t, naming.JoinAddressName(estr, "mounttable/a/b/falls"), "falls mainly on the plain", true, aliceID)
-	checkContents(t, naming.JoinAddressName(estr, "mounttable/a/b/falls"), "falls mainly on the plain", false, bobID)
+	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable//a/b"), collectionName, true, rootID)
+	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable/x/y"), collectionName, true, rootID)
+	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable/alpha//beta"), collectionName, true, rootID)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/falls"), "falls mainly on the plain", true, rootID)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/a/b/falls"), "falls mainly on the plain", true, rootID)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/x/y/falls"), "falls mainly on the plain", true, rootID)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/alpha/beta/falls"), "falls mainly on the plain", true, rootID)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/a/b/falls"), "falls mainly on the plain", true, aliceID)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/a/b/falls"), "falls mainly on the plain", false, bobID)
 
 	// Test generic unmount.
-	doUnmount(t, naming.JoinAddressName(estr, "//mounttable/a/b"), "", true, rootID)
-	checkContents(t, naming.JoinAddressName(estr, "mounttable/a/b/falls"), "falls mainly on the plain", false, rootID)
+	doUnmount(t, naming.JoinAddressName(mtAddr, "//mounttable/a/b"), "", true, rootID)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/a/b/falls"), "falls mainly on the plain", false, rootID)
 
 	// Test specific unmount.
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/a/b"), naming.JoinAddressName(estr, "collection"), true, rootID)
-	doUnmount(t, naming.JoinAddressName(estr, "//mounttable/a/b"), naming.JoinAddressName(estr, "collection"), true, rootID)
-	checkContents(t, naming.JoinAddressName(estr, "mounttable/a/b/falls"), "falls mainly on the plain", false, rootID)
+	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable/a/b"), collectionName, true, rootID)
+	doUnmount(t, naming.JoinAddressName(mtAddr, "//mounttable/a/b"), collectionName, true, rootID)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/a/b/falls"), "falls mainly on the plain", false, rootID)
 
 	// Try timing out a mount.
 	ft := NewFakeTimeClock()
 	setServerListClock(ft)
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/stuffWithTTL"), naming.JoinAddressName(estr, "collection"), true, rootID)
-	checkContents(t, naming.JoinAddressName(estr, "mounttable/stuffWithTTL/the/rain"), "the rain", true, rootID)
+	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable/stuffWithTTL"), collectionName, true, rootID)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuffWithTTL/the/rain"), "the rain", true, rootID)
 	ft.advance(time.Duration(ttlSecs+4) * time.Second)
-	checkContents(t, naming.JoinAddressName(estr, "mounttable/stuffWithTTL/the/rain"), "the rain", false, rootID)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuffWithTTL/the/rain"), "the rain", false, rootID)
 
 	// test unauthorized mount
-	doMount(t, naming.JoinAddressName(estr, "//mounttable//a/b"), naming.JoinAddressName(estr, "collection"), false, bobID)
-	doMount(t, naming.JoinAddressName(estr, "//mounttable//a/b"), naming.JoinAddressName(estr, "collection"), false, aliceID)
+	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable//a/b"), collectionName, false, bobID)
+	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable//a/b"), collectionName, false, aliceID)
 
-	doUnmount(t, naming.JoinAddressName(estr, "//mounttable/x/y"), naming.JoinAddressName(estr, "collection"), false, bobID)
+	doUnmount(t, naming.JoinAddressName(mtAddr, "//mounttable/x/y"), collectionName, false, bobID)
 }
 
 func doGlob(t *testing.T, name, pattern string, id ipc.ClientOpt) []string {
@@ -287,14 +309,14 @@
 }
 
 func TestGlob(t *testing.T) {
-	server, estr := newServer("", t)
+	server, estr := newMT(t, "")
 	defer server.Stop()
 
 	// set up a mount space
 	fakeServer := naming.JoinAddressName(estr, "quux")
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/one/bright/day"), fakeServer, true, rootID)
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/in/the/middle"), fakeServer, true, rootID)
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/of/the/night"), fakeServer, true, rootID)
+	doMount(t, naming.JoinAddressName(estr, "//one/bright/day"), fakeServer, true, rootID)
+	doMount(t, naming.JoinAddressName(estr, "//in/the/middle"), fakeServer, true, rootID)
+	doMount(t, naming.JoinAddressName(estr, "//of/the/night"), fakeServer, true, rootID)
 
 	// Try various globs.
 	tests := []struct {
@@ -311,19 +333,19 @@
 		{"", []string{""}},
 	}
 	for _, test := range tests {
-		out := doGlob(t, naming.JoinAddressName(estr, "//mounttable"), test.in, rootID)
+		out := doGlob(t, naming.JoinAddressName(estr, "//"), test.in, rootID)
 		checkMatch(t, test.expected, out)
 	}
 }
 
 func TestGlobACLs(t *testing.T) {
-	server, estr := newServer("testdata/test.acl", t)
+	server, estr := newMT(t, "testdata/test.acl")
 	defer server.Stop()
 
 	// set up a mount space
 	fakeServer := naming.JoinAddressName(estr, "quux")
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/one/bright/day"), fakeServer, true, rootID)
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/a/b/c"), fakeServer, true, rootID)
+	doMount(t, naming.JoinAddressName(estr, "//one/bright/day"), fakeServer, true, rootID)
+	doMount(t, naming.JoinAddressName(estr, "//a/b/c"), fakeServer, true, rootID)
 
 	// Try various globs.
 	tests := []struct {
@@ -339,13 +361,13 @@
 		{bobID, "*/...", []string{"one", "one/bright", "one/bright/day"}},
 	}
 	for _, test := range tests {
-		out := doGlob(t, naming.JoinAddressName(estr, "//mounttable"), test.in, test.id)
+		out := doGlob(t, naming.JoinAddressName(estr, "//"), test.in, test.id)
 		checkMatch(t, test.expected, out)
 	}
 }
 
 func TestServerFormat(t *testing.T) {
-	server, estr := newServer("", t)
+	server, estr := newMT(t, "")
 	defer server.Stop()
 
 	doMount(t, naming.JoinAddressName(estr, "//mounttable/endpoint"), naming.JoinAddressName(estr, "life/on/the/mississippi"), true, rootID)
@@ -357,15 +379,19 @@
 }
 
 func TestExpiry(t *testing.T) {
-	server, estr := newServer("", t)
+	server, estr := newMT(t, "")
 	defer server.Stop()
+	collection, collectionAddr := newCollection(t, "testdata/test.acl")
+	defer collection.Stop()
+
+	collectionName := naming.JoinAddressName(collectionAddr, "collection")
 
 	ft := NewFakeTimeClock()
 	setServerListClock(ft)
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/a1/b1"), naming.JoinAddressName(estr, "collection"), true, rootID)
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/a1/b2"), naming.JoinAddressName(estr, "collection"), true, rootID)
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/a2/b1"), naming.JoinAddressName(estr, "collection"), true, rootID)
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/a2/b2/c"), naming.JoinAddressName(estr, "collection"), true, rootID)
+	doMount(t, naming.JoinAddressName(estr, "//mounttable/a1/b1"), collectionName, true, rootID)
+	doMount(t, naming.JoinAddressName(estr, "//mounttable/a1/b2"), collectionName, true, rootID)
+	doMount(t, naming.JoinAddressName(estr, "//mounttable/a2/b1"), collectionName, true, rootID)
+	doMount(t, naming.JoinAddressName(estr, "//mounttable/a2/b2/c"), collectionName, true, rootID)
 
 	checkMatch(t, []string{"a1/b1", "a2/b1"}, doGlob(t, naming.JoinAddressName(estr, "//mounttable"), "*/b1/...", rootID))
 	ft.advance(time.Duration(ttlSecs/2) * time.Second)
@@ -373,7 +399,7 @@
 	checkMatch(t, []string{"c"}, doGlob(t, naming.JoinAddressName(estr, "//mounttable/a2/b2"), "*", rootID))
 	// Refresh only a1/b1.  All the other mounts will expire upon the next
 	// ft advance.
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/a1/b1"), naming.JoinAddressName(estr, "collection"), true, rootID)
+	doMount(t, naming.JoinAddressName(estr, "//mounttable/a1/b1"), collectionName, true, rootID)
 	ft.advance(time.Duration(ttlSecs/2+4) * time.Second)
 	checkMatch(t, []string{"a1"}, doGlob(t, naming.JoinAddressName(estr, "//mounttable"), "*", rootID))
 	checkMatch(t, []string{"a1/b1"}, doGlob(t, naming.JoinAddressName(estr, "//mounttable"), "*/b1/...", rootID))
diff --git a/services/mounttable/lib/neighborhood.go b/services/mounttable/lib/neighborhood.go
index b11588e..5f3a110 100644
--- a/services/mounttable/lib/neighborhood.go
+++ b/services/mounttable/lib/neighborhood.go
@@ -24,7 +24,6 @@
 // neighborhood defines a set of machines on the same multicast media.
 type neighborhood struct {
 	mdns   *mdns.MDNS
-	prefix string // mount point in the process namespace
 	nelems int
 }
 
@@ -59,7 +58,7 @@
 	return uint16(port)
 }
 
-func newNeighborhoodServer(prefix, host string, addresses []string, loopback bool) (*neighborhood, error) {
+func newNeighborhoodServer(host string, addresses []string, loopback bool) (*neighborhood, error) {
 	// Create the TXT contents with addresses to announce. Also pick up a port number.
 	var txt []string
 	var port uint16
@@ -87,20 +86,19 @@
 	mdns.AddService("veyron", "", port, txt...)
 
 	nh := &neighborhood{
-		mdns:   mdns,
-		prefix: prefix,
+		mdns: mdns,
 	}
 	return nh, nil
 }
 
 // NewLoopbackNeighborhoodServer creates a new instance of a neighborhood server on loopback interfaces for testing.
-func NewLoopbackNeighborhoodServer(prefix, host string, addresses ...string) (*neighborhood, error) {
-	return newNeighborhoodServer(prefix, host, addresses, true)
+func NewLoopbackNeighborhoodServer(host string, addresses ...string) (*neighborhood, error) {
+	return newNeighborhoodServer(host, addresses, true)
 }
 
 // NewNeighborhoodServer creates a new instance of a neighborhood server.
-func NewNeighborhoodServer(prefix, host string, addresses ...string) (*neighborhood, error) {
-	return newNeighborhoodServer(prefix, host, addresses, false)
+func NewNeighborhoodServer(host string, addresses ...string) (*neighborhood, error) {
+	return newNeighborhoodServer(host, addresses, false)
 }
 
 // Lookup implements ipc.Dispatcher.Lookup.
diff --git a/services/mounttable/lib/neighborhood_test.go b/services/mounttable/lib/neighborhood_test.go
index 707241b..471edba 100644
--- a/services/mounttable/lib/neighborhood_test.go
+++ b/services/mounttable/lib/neighborhood_test.go
@@ -31,6 +31,7 @@
 	if err != nil {
 		boom(t, "r.NewServer: %s", err)
 	}
+	defer server.Stop()
 
 	// Start serving on a loopback address.
 	e, err := server.Listen("tcp", "127.0.0.1:0")
@@ -44,20 +45,19 @@
 		naming.JoinAddressName(estr, "suffix2"),
 	}
 	// Add neighborhood server.
-	nhPrefix := "neighborhood"
-	nhd, err := NewLoopbackNeighborhoodServer(nhPrefix, "joeblow", addresses...)
+	nhd, err := NewLoopbackNeighborhoodServer("joeblow", addresses...)
 	if err != nil {
 		boom(t, "Failed to create neighborhood server: %s\n", err)
 	}
 	defer nhd.Stop()
-	if err := server.Register(nhPrefix, nhd); err != nil {
+	if err := server.Serve("", nhd); err != nil {
 		boom(t, "Failed to register neighborhood server: %s", err)
 	}
 
 	// Wait for the mounttable to appear in mdns
 L:
 	for tries := 1; tries < 2; tries++ {
-		names := doGlob(t, naming.JoinAddressName(estr, "//"+nhPrefix), "*", id)
+		names := doGlob(t, naming.JoinAddressName(estr, "//"), "*", id)
 		t.Logf("names %v", names)
 		for _, n := range names {
 			if n == "joeblow" {
@@ -67,18 +67,18 @@
 		time.Sleep(1 * time.Second)
 	}
 
-	want, got := []string{"joeblow"}, doGlob(t, naming.JoinAddressName(estr, "//neighborhood"), "*", id)
+	want, got := []string{"joeblow"}, doGlob(t, naming.JoinAddressName(estr, "//"), "*", id)
 	if !reflect.DeepEqual(want, got) {
 		t.Errorf("Unexpected Glob result want: %q, got: %q", want, got)
 	}
-	want, got = []string{""}, doGlob(t, naming.JoinAddressName(estr, "//neighborhood/joeblow"), "", id)
+	want, got = []string{""}, doGlob(t, naming.JoinAddressName(estr, "//joeblow"), "", id)
 	if !reflect.DeepEqual(want, got) {
 		t.Errorf("Unexpected Glob result want: %q, got: %q", want, got)
 	}
 
 	// Make sure we can resolve through the neighborhood.
 	expectedSuffix := "a/b"
-	objectPtr, err := mounttable.BindMountTable(naming.JoinAddressName(estr, "//neighborhood/joeblow"+"/"+expectedSuffix), quuxClient(id))
+	objectPtr, err := mounttable.BindMountTable(naming.JoinAddressName(estr, "//joeblow"+"/"+expectedSuffix), quuxClient(id))
 	if err != nil {
 		boom(t, "BindMountTable: %s", err)
 	}
diff --git a/services/mounttable/mounttabled/mounttable.go b/services/mounttable/mounttabled/mounttable.go
index 6d2061d..fadc4a8 100644
--- a/services/mounttable/mounttabled/mounttable.go
+++ b/services/mounttable/mounttabled/mounttable.go
@@ -6,7 +6,6 @@
 	"fmt"
 	"net"
 	"os"
-	"time"
 
 	"veyron2"
 	"veyron2/naming"
@@ -22,7 +21,6 @@
 	mountName = flag.String("name", "", "Name to mount this mountable as.  Empty means don't mount.")
 	// TODO(rthellend): Remove the address flag when the config manager is working.
 	address = flag.String("address", ":0", "Address to listen on.  Default is to use a randomly assigned port")
-	prefix  = flag.String("prefix", "mt", "The prefix to register the mounttable at.")
 	aclFile = flag.String("acls", "", "ACL file. Default is to allow all access.")
 	nhName  = flag.String("neighborhood_name", "", "If non-empty, publish in the local neighborhood under this name.")
 )
@@ -44,7 +42,7 @@
   <nh name>, if provided, will enable sharing with the local neighborhood with
   the provided name. The address of this mounttable will be published to the
   neighboorhood and everything in the neighborhood will be visible on this
-  mounttable with the "nh" prefix.
+  mounttable.
 `
 
 func Usage() {
@@ -52,8 +50,6 @@
 }
 
 func main() {
-	// TODO(cnicolaou): fix Usage so that it includes the flags defined by
-	// the runtime
 	flag.Usage = Usage
 	r := rt.Init()
 	defer r.Shutdown()
@@ -69,15 +65,22 @@
 		vlog.Errorf("r.NewMountTable failed: %v", err)
 		return
 	}
-	if err := mtServer.Register(*prefix, mt); err != nil {
-		vlog.Errorf("mtServer.Register failed to register mount table: %v", err)
-		return
-	}
 	mtEndpoint, err := mtServer.Listen("tcp", *address)
 	if err != nil {
 		vlog.Errorf("mtServer.Listen failed: %v", err)
 		return
 	}
+	name := *mountName
+	if err := mtServer.Serve(name, mt); err != nil {
+		vlog.Errorf("Serve(%v) failed: %v", name, err)
+		return
+	}
+	mtAddr := naming.JoinAddressName(mtEndpoint.String(), "")
+	r.Namespace().SetRoots(mtAddr)
+
+	vlog.Infof("Mount table service at: %q (%s)",
+		name,
+		naming.JoinAddressName(mtEndpoint.String(), ""))
 
 	if len(*nhName) > 0 {
 		nhServer, err := r.NewServer(veyron2.ServesMountTableOpt(true))
@@ -91,45 +94,19 @@
 			vlog.Errorf("parsing of address(%q) failed: %v", *address, err)
 			return
 		}
-		nhEndpoint, err := nhServer.Listen("tcp", net.JoinHostPort(host, "0"))
-		if err != nil {
+		if _, err = nhServer.Listen("tcp", net.JoinHostPort(host, "0")); err != nil {
 			vlog.Errorf("nhServer.Listen failed: %v", err)
 			return
 		}
-		mtAddr := naming.JoinAddressName(mtEndpoint.String(), *prefix)
-
 		nh, err := mounttable.NewNeighborhoodServer("", *nhName, mtAddr)
 		if err != nil {
 			vlog.Errorf("NewNeighborhoodServer failed: %v", err)
 			return
 		}
-		if err := nhServer.Register("", nh); err != nil {
-			vlog.Errorf("nhServer.Register failed to register neighborhood: %v", err)
+		if err := nhServer.Serve("nh", nh); err != nil {
+			vlog.Errorf("nhServer.Serve failed to register neighborhood: %v", err)
 			return
 		}
-		nhAddr := naming.JoinAddressName(nhEndpoint.String(), "")
-		nhMount := naming.Join(mtAddr, "nh")
-
-		ns := rt.R().Namespace()
-		forever := time.Duration(0)
-		if err = ns.Mount(rt.R().NewContext(), nhMount, nhAddr, forever); err != nil {
-			vlog.Errorf("ns.Mount failed to mount neighborhood: %v", err)
-			return
-		}
-	}
-
-	if name := *mountName; len(name) > 0 {
-		if err := mtServer.Publish(name); err != nil {
-			vlog.Errorf("Publish(%v) failed: %v", name, err)
-			return
-		}
-		vlog.Infof("Mount table service at: %s (%s)",
-			naming.Join(name, *prefix),
-			naming.JoinAddressName(mtEndpoint.String(), *prefix))
-
-	} else {
-		vlog.Infof("Mount table at: %s",
-			naming.JoinAddressName(mtEndpoint.String(), *prefix))
 	}
 
 	// Wait until signal is received.
diff --git a/services/security/simpledischarged/main.go b/services/security/simpledischarged/main.go
index cb9a840..bb1db9f 100644
--- a/services/security/simpledischarged/main.go
+++ b/services/security/simpledischarged/main.go
@@ -65,22 +65,14 @@
 
 	discharger := isecurity.NewServerDischarger(&discharged{
 		id: r.Identity(), expiration: expiration})
-	err = server.Register("discharged", ipc.SoloDispatcher(discharger, dischargeAuthorizer{}))
-	if err != nil {
-		log.Fatal(err)
-	}
-
+	dispatcher := ipc.SoloDispatcher(discharger, dischargeAuthorizer{})
 	endpoint, err := server.Listen(*protocol, *address+":"+fmt.Sprint(*port))
 	if err != nil {
 		log.Fatal(err)
 	}
-
-	if *publish != "" {
-		if err := server.Publish(*publish); err != nil {
-			log.Fatal(err)
-		}
+	if err := server.Serve(*publish, dispatcher); err != nil {
+		log.Fatal(err)
 	}
-
 	fmt.Println(endpoint)
 	<-signals.ShutdownOnSignals()
 }
diff --git a/services/store/stored/main.go b/services/store/stored/main.go
index 674fdf3..1d820b1 100644
--- a/services/store/stored/main.go
+++ b/services/store/stored/main.go
@@ -69,20 +69,15 @@
 
 	// Register the services.
 	storeDisp := server.NewStoreDispatcher(storeService, auth)
-	if err := s.Register("", storeDisp); err != nil {
-		log.Fatal("s.Register(storeDisp) failed: ", err)
-	}
-
 	// Create an endpoint and start listening.
 	ep, err := s.Listen("tcp", *address)
 	if err != nil {
 		log.Fatal("s.Listen() failed: ", err)
 	}
-
 	// Publish the service in the mount table.
 	log.Printf("Mounting store on %s, endpoint /%s", mountName, ep)
-	if err := s.Publish(mountName); err != nil {
-		log.Fatal("s.Publish() failed: ", err)
+	if err := s.Serve(mountName, storeDisp); err != nil {
+		log.Fatal("s.Serve() failed: ", err)
 	}
 
 	// Wait forever.
diff --git a/services/store/testutil/store.go b/services/store/testutil/store.go
index 1350312..a53fd88 100644
--- a/services/store/testutil/store.go
+++ b/services/store/testutil/store.go
@@ -2,7 +2,6 @@
 
 import (
 	"crypto/rand"
-	"fmt"
 	"io/ioutil"
 	"os"
 	"testing"
@@ -37,12 +36,9 @@
 		t.Fatalf("rand.Read() failed: %v", err)
 	}
 
-	name := fmt.Sprintf("test/%x", buf)
-	t.Logf("Storage server at %v", name)
-
 	// Register the services.
 	storeDispatcher := istore.NewStoreDispatcher(storeService, nil)
-	if err := server.Register(name, storeDispatcher); err != nil {
+	if err := server.Serve("", storeDispatcher); err != nil {
 		t.Fatalf("Register(%v) failed: %v", storeDispatcher, err)
 	}
 
@@ -53,8 +49,7 @@
 		t.Fatalf("Listen(%v, %v) failed: %v", protocol, hostname, err)
 	}
 
-	name = naming.JoinAddressName(ep.String(), name)
-	name = naming.MakeTerminal(name)
+	name := naming.JoinAddressName(ep.String(), "")
 
 	// Create a closure that cleans things up.
 	cleanup := func() {
diff --git a/services/wspr/wsprd/lib/server.go b/services/wspr/wsprd/lib/server.go
index 0497ae6..5fd89bf 100644
--- a/services/wspr/wsprd/lib/server.go
+++ b/services/wspr/wsprd/lib/server.go
@@ -6,7 +6,9 @@
 	"bytes"
 	"encoding/json"
 	"fmt"
+	"strings"
 	"sync"
+
 	"veyron2"
 	"veyron2/ipc"
 	"veyron2/security"
@@ -35,7 +37,9 @@
 
 	// The server that handles the ipc layer.  Listen on this server is
 	// lazily started.
-	server ipc.Server
+	server     ipc.Server
+	dispatcher exactMatchDispatcher
+
 	// The endpoint of the server.  This is empty until the server has been
 	// started and listen has been called on it.
 	endpoint string
@@ -57,6 +61,7 @@
 		helper:                    helper,
 		veyronProxy:               veyronProxy,
 		outstandingServerRequests: make(map[int64]chan *serverRPCReply),
+		dispatcher:                exactMatchDispatcher{dispatchers: make(map[string]ipc.Dispatcher)},
 	}
 	var err error
 	if server.server, err = helper.rt().NewServer(); err != nil {
@@ -141,12 +146,43 @@
 	}
 }
 
+type exactMatchDispatcher struct {
+	sync.Mutex
+	dispatchers map[string]ipc.Dispatcher
+}
+
+func (em *exactMatchDispatcher) Lookup(suffix string) (ipc.Invoker, security.Authorizer, error) {
+	parts := strings.Split(suffix, "/")
+	if len(parts) == 0 || len(parts[0]) == 0 {
+		return nil, nil, fmt.Errorf("can't extract first path component from %q", suffix)
+	}
+	name := parts[0]
+	em.Lock()
+	defer em.Unlock()
+	if disp := em.dispatchers[name]; disp == nil {
+		return nil, nil, fmt.Errorf("no dispatcher registered for %q, from %q", name, suffix)
+	} else {
+		suffix = strings.TrimLeft(suffix, "/")
+		suffix = strings.TrimPrefix(suffix, name[0])
+		suffix = strings.TrimLeft(suffix, "/")
+		return disp.Lookup(suffix)
+	}
+}
+
+// register associates a dispatcher with name, where name cannot contain
+// any /s. Incoming invocations of the form <name>/... will be passed
+// on to the dispatcher with <name>/... as the parameter to its lookup
+// method.
 func (s *server) register(name string, sig JSONServiceSignature) error {
 	serviceSig, err := sig.ServiceSignature()
 	if err != nil {
 		return err
 	}
 
+	if strings.Contains(name, "/") {
+		return fmt.Errorf("%q must not contain /", name)
+	}
+
 	remoteInvokeFunc := s.createRemoteInvokerFunc(name)
 	invoker, err := newInvoker(serviceSig, remoteInvokeFunc)
 
@@ -157,10 +193,9 @@
 		security.ACL{security.AllPrincipals: security.AllLabels},
 	))
 
-	if err := s.server.Register(name, dispatcher); err != nil {
-		return err
-	}
-
+	s.dispatcher.Lock()
+	s.dispatcher.dispatchers[name] = dispatcher
+	s.dispatcher.Unlock()
 	return nil
 }
 
@@ -175,7 +210,7 @@
 		}
 		s.endpoint = endpoint.String()
 	}
-	if err := s.server.Publish(name); err != nil {
+	if err := s.server.Serve(name, &s.dispatcher); err != nil {
 		return "", err
 	}
 	s.helper.getLogger().VI(1).Infof("endpoint is %s", s.endpoint)
diff --git a/services/wspr/wsprd/lib/wspr_test.go b/services/wspr/wsprd/lib/wspr_test.go
index 4ea681a..15d4ac3 100644
--- a/services/wspr/wsprd/lib/wspr_test.go
+++ b/services/wspr/wsprd/lib/wspr_test.go
@@ -91,40 +91,26 @@
 	return result, nil
 }
 
-// A function that will register an handlers on the given server
-type registerFunc func(ipc.Server) error
-
-func startServer(registerer registerFunc) (ipc.Server, naming.Endpoint, error) {
-	return startAnyServer(false, registerer)
-}
-
-func startMTServer(registerer registerFunc) (ipc.Server, naming.Endpoint, error) {
-	return startAnyServer(true, registerer)
-}
-
-func startAnyServer(servesMT bool, registerer registerFunc) (ipc.Server, naming.Endpoint, error) {
+func startAnyServer(servesMT bool, dispatcher ipc.Dispatcher) (ipc.Server, naming.Endpoint, error) {
 	// Create a new server instance.
 	s, err := r.NewServer(veyron2.ServesMountTableOpt(servesMT))
 	if err != nil {
 		return nil, nil, err
 	}
 
-	// Register the "fortune" prefix with the fortune dispatcher.
-	if err := registerer(s); err != nil {
-		return nil, nil, err
-	}
-
 	endpoint, err := s.Listen("tcp", "127.0.0.1:0")
 	if err != nil {
 		return nil, nil, err
 	}
+
+	if err := s.Serve("", dispatcher); err != nil {
+		return nil, nil, err
+	}
 	return s, endpoint, nil
 }
 
 func startAdderServer() (ipc.Server, naming.Endpoint, error) {
-	return startServer(func(server ipc.Server) error {
-		return server.Register("cache", ipc.SoloDispatcher(simpleAdder{}, nil))
-	})
+	return startAnyServer(false, ipc.SoloDispatcher(simpleAdder{}, nil))
 }
 
 func startProxy() (*proxy.Proxy, error) {
@@ -132,18 +118,15 @@
 	if err != nil {
 		return nil, err
 	}
-
 	return proxy.New(rid, nil, "tcp", "127.0.0.1:0", "")
 }
 
 func startMountTableServer() (ipc.Server, naming.Endpoint, error) {
-	return startMTServer(func(server ipc.Server) error {
-		mt, err := mounttable.NewMountTable("")
-		if err != nil {
-			return err
-		}
-		return server.Register("mt", mt)
-	})
+	mt, err := mounttable.NewMountTable("")
+	if err != nil {
+		return nil, nil, err
+	}
+	return startAnyServer(true, mt)
 }
 
 type testWriter struct {
@@ -251,7 +234,7 @@
 	wspr.setup()
 	wsp := websocketPipe{ctx: wspr}
 	wsp.setup()
-	jsSig, err := wsp.getSignature("/"+endpoint.String()+"//cache", "")
+	jsSig, err := wsp.getSignature("/"+endpoint.String(), "")
 	if err != nil {
 		t.Errorf("Failed to get signature: %v", err)
 	}
@@ -304,7 +287,7 @@
 	}
 
 	request := veyronRPC{
-		Name:        "/" + endpoint.String() + "//cache",
+		Name:        "/" + endpoint.String(),
 		Method:      test.method,
 		InArgs:      test.inArgs,
 		NumOutArgs:  test.numOutArgs,
@@ -396,7 +379,7 @@
 
 	proxyEndpoint := proxyServer.Endpoint().String()
 
-	wspr := NewWSPR(0, "/"+proxyEndpoint, veyron2.NamespaceRoots{"/" + endpoint.String() + "/mt"})
+	wspr := NewWSPR(0, "/"+proxyEndpoint, veyron2.NamespaceRoots{"/" + endpoint.String()})
 	wspr.setup()
 	wsp := websocketPipe{ctx: wspr}
 	writer := testWriter{
@@ -429,7 +412,8 @@
 	}
 
 	if len(rt.writer.stream) != 1 {
-		t.Errorf("expected only on response, got %d", len(rt.writer.stream))
+		t.Errorf("expected only one response, got %d", len(rt.writer.stream))
+		return
 	}
 
 	resp := rt.writer.stream[0]
@@ -516,6 +500,7 @@
 
 	if len(rt.writer.stream) != 1 {
 		t.Errorf("expected only on response, got %d", len(rt.writer.stream))
+		return
 	}
 
 	resp := rt.writer.stream[0]
@@ -558,7 +543,7 @@
 				"args":        test.inArgs,
 				"context": map[string]interface{}{
 					"name":   "adder",
-					"suffix": "",
+					"suffix": "adder",
 				},
 			},
 		},
diff --git a/tools/application/impl/impl_test.go b/tools/application/impl/impl_test.go
index 64b3f91..508df49 100644
--- a/tools/application/impl/impl_test.go
+++ b/tools/application/impl/impl_test.go
@@ -78,15 +78,15 @@
 		t.Errorf("NewServer failed: %v", err)
 		return nil, nil, err
 	}
-	if err := server.Register("", dispatcher); err != nil {
-		t.Errorf("Register failed: %v", err)
-		return nil, nil, err
-	}
 	endpoint, err := server.Listen("tcp", "localhost:0")
 	if err != nil {
 		t.Errorf("Listen failed: %v", err)
 		return nil, nil, err
 	}
+	if err := server.Serve("", dispatcher); err != nil {
+		t.Errorf("Serve failed: %v", err)
+		return nil, nil, err
+	}
 	return server, endpoint, nil
 }
 
diff --git a/tools/binary/impl/impl_test.go b/tools/binary/impl/impl_test.go
index 86595e1..70c0122 100644
--- a/tools/binary/impl/impl_test.go
+++ b/tools/binary/impl/impl_test.go
@@ -84,15 +84,15 @@
 		t.Errorf("NewServer failed: %v", err)
 		return nil, nil, err
 	}
-	if err := server.Register("", dispatcher); err != nil {
-		t.Errorf("Register failed: %v", err)
-		return nil, nil, err
-	}
 	endpoint, err := server.Listen("tcp", "localhost:0")
 	if err != nil {
 		t.Errorf("Listen failed: %v", err)
 		return nil, nil, err
 	}
+	if err := server.Serve("", dispatcher); err != nil {
+		t.Errorf("Serve failed: %v", err)
+		return nil, nil, err
+	}
 	return server, endpoint, nil
 }
 
diff --git a/tools/mounttable/impl/impl_test.go b/tools/mounttable/impl/impl_test.go
index 4af1d5f..d188797 100644
--- a/tools/mounttable/impl/impl_test.go
+++ b/tools/mounttable/impl/impl_test.go
@@ -59,15 +59,15 @@
 		t.Errorf("NewServer failed: %v", err)
 		return nil, nil, err
 	}
-	if err := server.Register("", dispatcher); err != nil {
-		t.Errorf("Register failed: %v", err)
-		return nil, nil, err
-	}
 	endpoint, err := server.Listen("tcp", "localhost:0")
 	if err != nil {
 		t.Errorf("Listen failed: %v", err)
 		return nil, nil, err
 	}
+	if err := server.Serve("", dispatcher); err != nil {
+		t.Errorf("Serve failed: %v", err)
+		return nil, nil, err
+	}
 	return server, endpoint, nil
 }
 
diff --git a/tools/naming/simulator/clock.scr b/tools/naming/simulator/clock.scr
index 2df07af..ac1dd39 100644
--- a/tools/naming/simulator/clock.scr
+++ b/tools/naming/simulator/clock.scr
@@ -3,24 +3,24 @@
 # and with a mount table.
 #
 
-# A 'stand-alone' server, with an internal namespace of 'mt/...'
-clockServer "" mt clock
+# A 'stand-alone' server
+clockServer "" ""
 set STAND_ALONE_CLOCK_NAME=$NAME
 
 set N=$STAND_ALONE_CLOCK_NAME
 print "Stand alone clock server at" $N
 time $N "Using $N"
-set N=/$ADDR//mt
+set N=/$ADDR
 time $N "Using $N"
 
 # Run a root MountTable.
-rootMT mt
+rootMT
 set ROOT_ADDR=$MT_ADDR ROOT_NAME=$MT_NAME
 print ""
 print "Root MountTable at $ROOT_NAME"
 
-clockServer $MT_NAME clocks home_clock
-set CLOCK_NAME=/$ADDR//clocks
+clockServer $MT_NAME clock
+set CLOCK_NAME=/$ADDR
 print "Running Clock Server at $CLOCK_NAME"
 
 # Still bypassing the MountTable
@@ -29,26 +29,17 @@
 # Now, let's use the MountTable
 setLocalRoots $ROOT_NAME
 
-set N=home_clock
+set N=clock
 resolve $N
 print $N -> $R0
 
-set N=home_clock/clocks
+set N=/$ROOT_ADDR/clock
 resolve $N
 print $N -> $R0
 
-set N=/$ROOT_ADDR/home_clock/clocks
-resolve $N
-print $N -> $R0
-
-set N=home_clock/clocks
-time $N "Using $N"
-set N=$ROOT_NAME/home_clock/clocks
-time $N "Using $N"
-
-# ls * returns home_clock
+# ls * returns clock
 ls *
-# ls ... returns "" and home_clock - i.e two items. Is this a bug?
+# ls ... returns "" and clock - i.e two items. Is this a bug?
 ls ...
 
 # These all behave as above
diff --git a/tools/naming/simulator/mt.scr b/tools/naming/simulator/mt.scr
index cdb8b07..6f89f70 100644
--- a/tools/naming/simulator/mt.scr
+++ b/tools/naming/simulator/mt.scr
@@ -2,34 +2,33 @@
 # Example showing multiple mount tables, servers and globing
 #
 
-rootMT ""
+rootMT
 set ROOT_MT_NAME=$MT_NAME ROOT_MT_ADDR=$MT_ADDR
 set ROOT=$ROOT_MT_NAME
 
-nodeMT $ROOT "mt" "usa"
+nodeMT $ROOT usa
 set USA_MT=$MT_NAME
 
-nodeMT $USA_MT_NAME "mt" "palo alto"
+nodeMT $USA_MT "palo alto"
 set PA_MT=$MT_NAME
 
 
-print "--------- Resolve ROOT, ROOT/usa, ROOT/usa/mt/palo alto"
+print "ROOT MT" $ROOT
+print "USA MT" $USA_MT
+print "Palo Alto MT" $PA_MT
+
+print "--------- Resolve ROOT, ROOT/usa, ROOT/usa/palo alto"
 print "--------- Each should return a different address"
 resolve $ROOT
 resolve $ROOT/usa
-resolve "$ROOT/usa/mt/palo alto"
+resolve "$ROOT/usa/palo alto"
 
-print "--------- ResolveMT ROOT, ROOT/usa, ROOT/usa/mt - should return the ROOT MT"
+print "--------- ResolveMT ROOT, ROOT/usa - should return the ROOT MT"
 resolveMT $ROOT
 resolveMT $ROOT/usa
-resolveMT $ROOT/usa/mt
 
-print "--------- ResolveMT ROOT/usa/mt/palo alto, palo alto/mt should return the USA MT"
-resolveMT "$ROOT/usa/mt/palo alto"
-resolveMT "$ROOT/usa/mt/palo alto/mt"
-
-print "--------- ResolveMT ROOT/usa/mt/palo alto/mt/bar should return the palo alto MT"
-resolveMT "$ROOT/usa/mt/palo alto/mt/bar"
+print "--------- ResolveMT ROOT/usa/palo alto/bar should return the palo alto MT"
+resolveMT "$ROOT/usa/palo alto/bar"
 
 # should return a complete hiearchy....
 setLocalRoots $ROOT
@@ -47,10 +46,10 @@
 setLocalRoots $PA_MT
 ls ...
 
-nodeMT $ROOT "mt" "uk"
+nodeMT $ROOT uk
 set UK_MT=$MT_NAME
 
-nodeMT $UK_MT "mt" "cambridge"
+nodeMT $UK_MT "cambridge"
 set CAM_MT=$MT_NAME
 
 setLocalRoots $ROOT
@@ -62,20 +61,14 @@
 
 # Create a MountTable tree without using the internal 'mt' suffix as in the
 # examples above.
-nodeMT $ROOT "" "france"
+nodeMT $ROOT "france"
 set FRANCE_MT=$MT_NAME
-nodeMT $FRANCE_MT "" "paris"
+nodeMT $FRANCE_MT "paris"
 setLocalRoots $ROOT
 ls ...
 
 # Conclusion: some of this behaviour seems a little awkward. In particular:
 #
-# ls (i.e. glob) ... on the root doesn't seem to iterate down the name
-# space hierarchy, I was under the impression that the local MountTable
-# client would do so? Well, it turns out that this only works if the
-# internal suffix (mt in the USA/UK trees, empty in the France tree) is
-# empty!!
-#
 # ls using the local namespace on a rooted name doesn't seem to work either,
 # thus making it impossible to see the whole name space without setting the
 # local namespace's root which will clearly cause problems for concurrent
diff --git a/tools/profile/impl/impl_test.go b/tools/profile/impl/impl_test.go
index e0d179a..8500787 100644
--- a/tools/profile/impl/impl_test.go
+++ b/tools/profile/impl/impl_test.go
@@ -88,15 +88,15 @@
 		t.Errorf("NewServer failed: %v", err)
 		return nil, nil, err
 	}
-	if err := server.Register("", dispatcher); err != nil {
-		t.Errorf("Register failed: %v", err)
-		return nil, nil, err
-	}
 	endpoint, err := server.Listen("tcp", "localhost:0")
 	if err != nil {
 		t.Errorf("Listen failed: %v", err)
 		return nil, nil, err
 	}
+	if err := server.Serve("", dispatcher); err != nil {
+		t.Errorf("Serve failed: %v", err)
+		return nil, nil, err
+	}
 	return server, endpoint, nil
 }
 
diff --git a/tools/proximity/impl/impl_test.go b/tools/proximity/impl/impl_test.go
index d22fbb3..460cd83 100644
--- a/tools/proximity/impl/impl_test.go
+++ b/tools/proximity/impl/impl_test.go
@@ -53,15 +53,15 @@
 		t.Errorf("NewServer failed: %v", err)
 		return nil, nil, err
 	}
-	if err := server.Register("", dispatcher); err != nil {
-		t.Errorf("Register failed: %v", err)
-		return nil, nil, err
-	}
 	endpoint, err := server.Listen("tcp", "localhost:0")
 	if err != nil {
 		t.Errorf("Listen failed: %v", err)
 		return nil, nil, err
 	}
+	if err := server.Serve("", dispatcher); err != nil {
+		t.Errorf("Serve failed: %v", err)
+		return nil, nil, err
+	}
 	return server, endpoint, nil
 }
 
diff --git a/tools/vrpc/impl/impl_test.go b/tools/vrpc/impl/impl_test.go
index f2dcea8..262f3e8 100644
--- a/tools/vrpc/impl/impl_test.go
+++ b/tools/vrpc/impl/impl_test.go
@@ -131,17 +131,14 @@
 		t.Errorf("NewServer failed: %v", err)
 		return nil, nil, err
 	}
-	if err := server.Register("", dispatcher); err != nil {
-		t.Errorf("Register failed: %v", err)
-		return nil, nil, err
-	}
+
 	endpoint, err := server.Listen("tcp", "localhost:0")
 	if err != nil {
 		t.Errorf("Listen failed: %v", err)
 		return nil, nil, err
 	}
-	if err := server.Publish(""); err != nil {
-		t.Errorf("Publish failed: %v", err)
+	if err := server.Serve("", dispatcher); err != nil {
+		t.Errorf("Serve failed: %v", err)
 		return nil, nil, err
 	}
 	return server, endpoint, nil