MCP Service -- Host and Manage MCP Servers
Host production MCP servers with OAuth authentication, tool discovery, capability negotiation, and streamable HTTP transport for Claude Desktop and Claude Code.
On this page
TL;DR: systemprompt.io hosts production MCP (Model Context Protocol) servers as standalone Rust binaries with OAuth authentication, typed tool schemas, and streamable HTTP transport. Each server registers tools that AI models discover and invoke automatically. The platform handles routing, authentication, RBAC enforcement, artifact persistence, and integration with clients like Claude Desktop and Claude Code.
What MCP Is and Why It Matters
AI models reason well but cannot act on the world directly. They cannot query databases, call APIs, manage files, or interact with external systems without tooling. The Model Context Protocol (MCP) is an open standard that solves this by defining how AI clients discover and invoke tools hosted on remote servers.
MCP matters because it replaces ad-hoc tool integrations with a single protocol. Instead of building custom integrations for every AI client, you build one MCP server and every compatible client -- Claude Desktop, Claude Code, or any other -- can use it immediately.
systemprompt.io takes this further. Rather than running MCP servers as local stdio processes, the platform hosts them as authenticated HTTP services. This means your tools are available from anywhere, secured by OAuth, and managed through a unified control plane.
Architecture
MCP in systemprompt.io follows a client-server model with three layers:
┌─────────────────────┐ ┌──────────────────────┐ ┌─────────────────┐
│ AI Client │ │ systemprompt.io │ │ MCP Server │
│ (Claude Desktop, │────▶│ Router + OAuth │────▶│ (Rust binary) │
│ Claude Code) │ │ /api/v1/mcp/{name}/ │ │ port 5010 │
└─────────────────────┘ └──────────────────────┘ └─────────────────┘
- MCP Server -- A Rust binary implementing
ServerHandlerfrom thermcpcrate. Exposes tools, resources, and capabilities over the MCP protocol. - Router -- An Axum HTTP layer that terminates streamable HTTP transport, enforces OAuth, and proxies requests to the correct server process.
- AI Client -- Any MCP-compatible client that connects over HTTP, discovers tools, and calls them during conversations.
Each server runs as an independent process on its own configured port. The platform router maps /api/v1/mcp/{server-name}/mcp to the correct backend.
Server Hosting with OAuth
Every MCP server is configured with a YAML manifest and an optional OAuth policy. The platform enforces authentication before any tool call reaches your handler code.
Manifest Configuration
Each server has a manifest.yaml in its extension directory:
# extensions/mcp/systemprompt/manifest.yaml
extension:
type: mcp
name: systemprompt
binary: systemprompt-mcp-agent
description: systemprompt.io MCP Agent for executing CLI commands (admin only)
port: 5010
build_type: workspace
enabled: true
OAuth Configuration
OAuth is configured per-server in the service YAML files under services/mcp/:
mcp_servers:
systemprompt:
type: internal
binary: systemprompt-mcp-agent
package: systemprompt
port: 5010
enabled: true
display_in_web: true
description: systemprompt.io MCP Server - Execute CLI commands (admin only)
oauth:
required: true
scopes: ["admin"]
audience: "mcp"
| OAuth Field | Type | Description |
|---|---|---|
required |
boolean | Enforce authentication on all tool calls |
scopes |
string[] | Required OAuth scopes (e.g., admin, user, tools:read) |
audience |
string | Expected JWT audience claim |
client_id |
string | Optional restriction to a specific OAuth client |
When oauth.required is true, the platform middleware calls enforce_rbac_from_registry before dispatching to the server handler. Unauthenticated requests are rejected before your code runs.
Server Configuration Fields
| Field | Type | Description |
|---|---|---|
binary |
string | Compiled binary name |
package |
string | Cargo package/crate name |
port |
number | Listening port |
enabled |
boolean | Whether the server is active |
display_in_web |
boolean | Show in the admin web UI |
description |
string | Human-readable server description |
Tool Discovery and Capability Negotiation
MCP servers advertise their capabilities during the initialization handshake. When a client connects, it receives the server's protocol version, supported capabilities, and metadata.
Initialization Response
Every server implements get_info() which returns:
- Protocol version -- The shipped server advertises
V_2024_11_05via thermcpcrate - Capabilities -- Which features the server supports (tools, resources, experimental)
- Server info -- Name, version, icons, website URL
- Instructions -- Guidance for the AI model on how to use the server
Tool Listing
Clients call tools/list to discover available tools. Each tool is defined with:
- Name and title -- Machine-readable identifier and human-readable label
- Description -- Detailed usage instructions for the AI model
- Input schema -- JSON Schema defining required and optional parameters
- Output schema -- JSON Schema describing the response structure
- UI metadata -- Hints for rendering in visual clients
Resource Listing
Servers can also expose resources (static or dynamic content) through resources/list and resources/read. For example, the systemprompt server exposes an artifact viewer as a UI resource with content security policies.
Discovery Endpoints
| Endpoint | Description |
|---|---|
/api/v1/mcp/registry |
List all registered MCP servers |
/api/v1/mcp/{server}/mcp |
Individual server endpoint (streamable HTTP) |
The AI service uses the registry endpoint to auto-discover servers and make their tools available to agents.
Building MCP Servers
MCP servers in systemprompt.io are Rust binaries built with the rmcp crate. The platform provides helper utilities for routing, OAuth enforcement, response building, and artifact persistence.
Project Structure
extensions/mcp/systemprompt/
├── Cargo.toml
├── manifest.yaml
└── src/
├── main.rs # Entry point: config, listener, router
├── lib.rs # Re-exports server type
├── cli.rs # CLI subprocess execution
├── error.rs # Error types
├── server/
│ ├── mod.rs # ServerHandler implementation
│ └── tool.rs # Tool dispatch with RBAC enforcement
└── tools.rs # Tool definitions (schema, metadata)
Entry Point
The main.rs initializes configuration, creates the server, builds the router, and starts listening:
let server = SystempromptServer::new(
Arc::clone(ctx.db_pool()),
service_id.clone(),
Arc::clone(ctx.authz_hook()),
)?;
let router = systemprompt::mcp::create_router(
server,
ctx.db_pool(),
systemprompt::mcp::McpHttpConfig::default(),
);
let listener = TcpListener::bind(&addr).await?;
axum::serve(listener, router).await?;
The create_router function wraps the server handler with streamable HTTP transport and OAuth middleware.
Implementing ServerHandler
Each server implements the ServerHandler trait from rmcp:
impl ServerHandler for SystempromptServer {
fn get_info(&self) -> ServerInfo { /* capabilities */ }
async fn initialize(&self, request, ctx) -> Result<InitializeResult, McpError> { ... }
async fn list_tools(&self, request, ctx) -> Result<ListToolsResult, McpError> { ... }
async fn call_tool(&self, request, ctx) -> Result<CallToolResult, McpError> { ... }
async fn list_resources(&self, request, ctx) -> Result<ListResourcesResult, McpError> { ... }
async fn read_resource(&self, request, ctx) -> Result<ReadResourceResult, McpError> { ... }
}
Inside call_tool, enforce authentication before processing:
let auth_result = enforce_rbac_from_registry(&ctx, self.service_id.as_str(), &self.authz_hook)
.await?
.expect_authenticated("requires OAuth")?;
Defining Tools
Each tool has typed input and output schemas derived from JsonSchema structs via schemars, never hand-rolled JSON blobs:
#[must_use]
pub fn input_schema() -> serde_json::Value {
schemars::schema_for!(CliInput).to_value()
}
#[must_use]
pub fn output_schema() -> serde_json::Value {
ToolResponse::<CliArtifact>::schema()
}
Tools are registered in the list_tools() function of the tools module and dispatched by name in call_tool.
Available MCP Servers
The template ships with one MCP server:
| Server | Port | Tools | Purpose |
|---|---|---|---|
systemprompt |
5010 | systemprompt (CLI executor) |
Execute CLI commands with artifact rendering (admin only) |
Additional servers are added as extension crates under extensions/mcp/ with matching YAML under services/mcp/.
Integration with Claude Desktop and Claude Code
Claude Desktop
Add your MCP server to the Claude Desktop configuration file:
{
"mcpServers": {
"systemprompt": {
"url": "https://your-domain.com/api/v1/mcp/systemprompt/mcp",
"transport": "streamable-http"
}
}
}
For local development, use http://localhost:8080/api/v1/mcp/systemprompt/mcp.
Claude Code
Claude Code supports MCP servers through its configuration. Add the server URL and it will discover tools automatically during sessions.
Any MCP Client
Any client that supports the MCP protocol over streamable HTTP can connect. The server responds to standard MCP methods: initialize, tools/list, tools/call, resources/list, and resources/read.
Security Model
MCP security in systemprompt.io operates at multiple layers:
- Transport security -- HTTPS in production. All endpoints behind TLS.
- OAuth authentication -- JWT tokens validated on every tool call. Configurable scopes and audience per server.
- RBAC enforcement -- The
enforce_rbac_from_registrymiddleware checks the token against the server's registered OAuth policy before dispatching to the handler. - Scope-based access control -- Common scope patterns:
admin-- Full administrative accessuser-- Standard user operationstools:read-- Read-only tool accesstools:write-- Tool execution permission
- Per-server isolation -- Each server runs as a separate process with its own port, database pool, and service dependencies.
- Secret encryption -- Secrets (managed via
systemprompt admin config secret) are encrypted at rest in the database. - Content Security Policy -- UI resources served by MCP servers include strict CSP headers.
Managing MCP Servers
Applying Configuration Changes
MCP server YAML files under services/mcp/ are ingested into the database at server startup. After modifying them, restart the services:
systemprompt infra services restart
Validate the configuration first with systemprompt plugins mcp validate.
Building Servers
MCP servers are built as part of the workspace:
# Build all MCP servers
systemprompt build mcp
# Build a specific server
cargo build --package systemprompt-mcp-agent --release
CLI Reference
| Command | Description |
|---|---|
systemprompt plugins mcp list |
List MCP server configurations |
systemprompt plugins mcp status |
Show MCP server runtime status |
systemprompt plugins mcp tools [--server <name>] |
List tools exposed by enabled servers |
systemprompt plugins mcp call <server> <tool> |
Invoke a tool on an MCP server |
systemprompt plugins mcp validate |
Validate MCP server configurations |
systemprompt plugins mcp logs <name> |
View MCP server logs |
systemprompt plugins mcp list-packages |
List package names for build |
Run systemprompt plugins mcp <command> --help for detailed options.
Troubleshooting
Server not discovered -- Verify enabled: true in the manifest. Check that the endpoint is accessible and the AI service has auto_discover: true set.
Tool execution fails -- Inspect server logs with systemprompt plugins mcp logs <name>. Confirm the OAuth token carries the required scopes. Increase timeout settings for long-running tools.
Authentication errors -- Ensure the client token includes the correct scopes and audience. Cross-check the oauth block in the server's YAML configuration.
Connection refused -- Confirm the server process is running on the expected port. Use systemprompt plugins mcp status to check binary and port status.
Build failures -- Run systemprompt plugins mcp list-packages to verify package names. Check that Cargo.toml dependencies are up to date.
Related Documentation
- MCP Tool Structure -- How tools are defined and structured
- MCP Responses -- Response building and artifact persistence
- MCP Resources -- Exposing resources from MCP servers
- MCP Skills -- Skill integration with MCP tools
- MCP Domain Extension -- The MCP extension domain
- MCP-AI Integration -- How MCP connects to the AI service
- Connect MCP Guide -- Step-by-step guide for connecting clients
- AI Service -- The AI service that consumes MCP tools