mcpserver

package
v0.12.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 27, 2026 License: Apache-2.0 Imports: 28 Imported by: 0

README

HTCondor MCP Server

A Model Context Protocol (MCP) server for managing HTCondor jobs. This server exposes HTCondor functionality as MCP tools that can be used by AI assistants and other MCP clients.

Features

  • Job Submission: Submit jobs via MCP tool with HTCondor submit file
  • Job Queries: List and retrieve job details with ClassAd constraints and projections
  • Job Management: Remove, edit, hold, and release jobs
  • Authentication: Token-based authentication forwarded to HTCondor schedd
  • Demo Mode: Built-in mini HTCondor setup for testing and development
  • MCP Protocol: Full MCP protocol support for seamless AI integration

What is MCP?

The Model Context Protocol (MCP) is an open standard that enables AI assistants to securely interact with external data sources and tools. MCP servers expose specific capabilities (called "tools" and "resources") that AI assistants can discover and use.

Installation

cd cmd/htcondor-mcp
go build

Usage

Normal Mode (with existing HTCondor)
# Uses HTCondor configuration from environment
./htcondor-mcp

The server will:

  1. Read HTCondor configuration from standard locations
  2. Connect to the configured schedd
  3. Listen on stdin/stdout for MCP protocol messages
Demo Mode (standalone mini HTCondor)
# Starts mini HTCondor automatically
./htcondor-mcp --demo

Demo mode will:

  1. Create a temporary directory for mini HTCondor
  2. Write minimal HTCondor configuration
  3. Start condor_master as a subprocess
  4. Start the MCP server
  5. Clean up on Ctrl+C or SIGTERM

MCP Tools

The server provides the following MCP tools:

submit_job

Submit an HTCondor job using a submit file.

Input:

  • submit_file (string, required): HTCondor submit file content

Example:

{
  "name": "submit_job",
  "arguments": {
    "submit_file": "executable = /bin/echo\ntransfer_executable = False\narguments = Hello World\nqueue"
  }
}

Two submit-language rules: a system-path executable requires transfer_executable = False (submit_job rejects it otherwise, since HTCondor would spool-copy an executable that is not there and the job would hold), and $(...) is macro expansion, not shell substitution — to run shell commands, upload a script with upload_job_input and name it as the executable. submit_job warns about $(...) references nothing defines.

query_jobs

Query HTCondor jobs with optional constraints and projections.

Input:

  • constraint (string, optional): ClassAd constraint expression (default: 'true')
  • projection (array of strings, optional): Attributes to include in results

Example:

{
  "name": "query_jobs",
  "arguments": {
    "constraint": "Owner == \"alice\"",
    "projection": ["ClusterId", "ProcId", "JobStatus", "Owner"]
  }
}
get_job

Get details of a specific HTCondor job by ID.

Input:

  • job_id (string, required): Job ID in format 'cluster.proc' (e.g., '123.0')

Example:

{
  "name": "get_job",
  "arguments": {
    "job_id": "123.0"
  }
}
remove_job

Remove (delete) a specific HTCondor job.

Input:

  • job_id (string, required): Job ID in format 'cluster.proc'
  • reason (string, optional): Reason for removal
remove_jobs

Remove multiple HTCondor jobs matching a constraint.

Input:

  • constraint (string, required): ClassAd constraint to select jobs
  • reason (string, optional): Reason for removal
edit_job

Edit attributes of a specific HTCondor job.

Input:

  • job_id (string, required): Job ID in format 'cluster.proc'
  • attributes (object, required): Attributes to update as key-value pairs

Example:

{
  "name": "edit_job",
  "arguments": {
    "job_id": "123.0",
    "attributes": {
      "JobPrio": 10,
      "UserNote": "High priority job"
    }
  }
}
hold_job

Hold a specific HTCondor job.

Input:

  • job_id (string, required): Job ID in format 'cluster.proc'
  • reason (string, optional): Reason for holding
release_job

Release a held HTCondor job.

Input:

  • job_id (string, required): Job ID in format 'cluster.proc'
  • reason (string, optional): Reason for release

MCP Resources

condor://schedd/status

Returns the current status and information about the HTCondor schedd from the collector.

Integration with AI Assistants

VS Code with GitHub Copilot

Add to your .vscode/mcp.json:

{
  "mcpServers": {
    "htcondor": {
      "command": "/path/to/htcondor-mcp",
      "args": ["--demo"]
    }
  }
}
Claude Desktop

Add to your Claude Desktop configuration:

{
  "mcpServers": {
    "htcondor": {
      "command": "/path/to/htcondor-mcp"
    }
  }
}

Authentication

The MCP server authenticates callers at the transport: an HTTP caller presents a bearer token (an OAuth2 token from the built-in issuer, or a pool IDTOKEN that the schedd verifies), and a stdio caller is whoever the process runs as, using ambient HTCondor configuration and filesystem auth.

In demo mode, the server uses a signing key for token generation. In normal mode, it uses the HTCondor configuration to locate tokens and signing keys.

Configuration

The server reads HTCondor configuration from standard locations:

  • CONDOR_CONFIG environment variable
  • /etc/condor/condor_config
  • ~/.condor/user_config

Key configuration parameters:

  • SCHEDD_NAME: Name of the schedd to connect to
  • COLLECTOR_HOST: Collector address for schedd discovery
  • SEC_TOKEN_POOL_SIGNING_KEY_FILE: Path to token signing key
  • TRUST_DOMAIN: Trust domain for tokens
  • UID_DOMAIN: UID domain for user identification

Comparison with HTTP API

Feature HTTP API MCP Server
Protocol REST/HTTP MCP (JSON-RPC over stdio)
Transport Network (TCP) stdio pipes
Authentication Bearer tokens Token in tool arguments
Discovery OpenAPI schema MCP tools/resources list
Use Case Web clients, curl AI assistants, MCP clients
Deployment Standalone server Subprocess of client

Development

Building
go build -o htcondor-mcp cmd/htcondor-mcp/main.go
Testing
# Test in demo mode
./htcondor-mcp --demo

# Send MCP messages via stdin (initialize protocol)
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' | ./htcondor-mcp

License

See LICENSE file in the repository root.

Documentation

Overview

Package mcpserver implements the Model Context Protocol (MCP) server for HTCondor.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsReadOnlyTool

func IsReadOnlyTool(name string) bool

IsReadOnlyTool reports whether the named MCP tool is in the read-only allowlist. Used by both the in-package scope filter on tools/list and the httpserver-side OAuth2 scope check on tools/call. Putting the canonical list in this package keeps the two paths from drifting.

func WithGrantedScopes

func WithGrantedScopes(ctx context.Context, scopes []string) context.Context

WithGrantedScopes attaches the OAuth2-granted scope set to a context. Used by the HTTP MCP transport to feed the scope filter in handleListTools.

Types

type Config

type Config struct {
	ScheddName string // Schedd name
	ScheddAddr string // Schedd address (e.g., "127.0.0.1:9618"). If empty, discovered from collector.
	// ScheddHost is the SCHEDD_HOST setting: the host (optionally
	// "name@host", optionally with a port) whose schedd this server
	// should talk to. Consulted when neither ScheddAddr nor ScheddName
	// is set, and it selects that host's schedd rather than whichever
	// one the collector lists first.
	ScheddHost      string
	Schedd          *htcondor.Schedd     // Pre-configured Schedd instance (optional, if provided, ScheddName/ScheddAddr are ignored)
	SigningKeyPath  string               // Path to token signing key (optional, for token generation)
	TrustDomain     string               // Trust domain for token issuer (optional)
	UIDDomain       string               // UID domain for generated token username (optional)
	HTTPBaseURL     string               // Base URL for HTTP API (e.g., "http://localhost:8080") for file download links
	Collector       *htcondor.Collector  // Collector for metrics and discovery (optional)
	Credd           htcondor.CreddClient // Optional credd client for credential management
	Instructions    string               // Server-level instructions provided to all agents in the MCP initialize response
	EnableMetrics   bool                 // Enable metrics collection (default: true if Collector is set)
	MetricsCacheTTL time.Duration        // Metrics cache TTL (default: 10s)
	Logger          *logging.Logger      // Logger instance (optional, creates default if nil)
	Stdin           io.Reader            // Input stream (default: os.Stdin)
	Stdout          io.Writer            // Output stream (default: os.Stdout)
	// AdminUsers is the list of authenticated subjects (JWT `sub` /
	// authenticated username) who get admin treatment in tool
	// dispatch — most importantly, they are exempt from the
	// per-tool owner-scope wrapper that otherwise restricts queries
	// and mutations to the caller's own jobs. Match must be exact
	// against the value returned by
	// htcondor.GetAuthenticatedUserFromContext (typically
	// "user@uid.domain"). Empty list = no admin users (default).
	AdminUsers []string

	// HTCondorConfig is the ambient HTCondor configuration. When set (together with a
	// Collector), the htcondordb-backed tools are enabled: the server discovers the database
	// via the collector and authenticates to it using this config's SEC_* knobs. nil disables
	// those tools.
	HTCondorConfig *config.Config

	// Delegated marks a server that acts on behalf of remote callers
	// rather than running as the user, which is the case when webapi
	// embeds it behind HTTP. It changes what an unknown caller means:
	// a delegated server must refuse an owner-scoped tool it cannot
	// confine, while a server run from a user's shell over stdio is
	// already confined by being that user's process. Default false, so
	// the stdio CLI keeps working exactly as before.
	Delegated bool

	// htcondordb mirror routing, mirroring the REST handler's config of
	// the same name so one daemon routes both surfaces identically. See
	// dbmirror.Options.
	DBMirrorName     string // HTTP_API_DBMIRROR_NAME
	DBMirrorAddress  string // HTTP_API_DBMIRROR_ADDRESS
	DBMirrorRequired bool   // HTTP_API_DBMIRROR_REQUIRED
}

Config holds server configuration

type MCPError

type MCPError struct {
	Code    int         `json:"code"`
	Message string      `json:"message"`
	Data    interface{} `json:"data,omitempty"`
}

MCPError represents an MCP error

type MCPMessage

type MCPMessage struct {
	JSONRPC string          `json:"jsonrpc"`
	ID      interface{}     `json:"id,omitempty"`
	Method  string          `json:"method,omitempty"`
	Params  json.RawMessage `json:"params,omitempty"`
	Result  interface{}     `json:"result,omitempty"`
	Error   *MCPError       `json:"error,omitempty"`
}

MCPMessage represents an MCP protocol message

type OutputFile

type OutputFile struct {
	Filename    string `json:"filename"`
	Data        string `json:"data"`
	IsTruncated bool   `json:"is_truncated"`
	URL         string `json:"url,omitempty"`
	IsBase64    bool   `json:"is_base64"`
	Size        int64  `json:"size"`
}

OutputFile represents a file from the job's output sandbox

type Resource

type Resource struct {
	URI         string `json:"uri"`
	Name        string `json:"name"`
	Description string `json:"description"`
	MimeType    string `json:"mimeType,omitempty"`
}

Resource represents an MCP resource

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server represents the MCP server

func NewServer

func NewServer(cfg Config) (*Server, error)

NewServer creates a new MCP server

func (*Server) HandleMessage

func (s *Server) HandleMessage(ctx context.Context, msg *MCPMessage) *MCPMessage

HandleMessage is the public interface for handling MCP messages (used by HTTP handler)

func (*Server) Run

func (s *Server) Run(ctx context.Context) error

Run starts the MCP server and processes messages

func (*Server) SetStdin

func (s *Server) SetStdin(stdin io.Reader) io.Reader

SetStdin sets the input stream for the MCP server and returns the previous stream

func (*Server) SetStdout

func (s *Server) SetStdout(stdout io.Writer) io.Writer

SetStdout sets the output stream for the MCP server and returns the previous stream

type Tool

type Tool struct {
	Name        string                 `json:"name"`
	Description string                 `json:"description"`
	InputSchema map[string]interface{} `json:"inputSchema"`
}

Tool represents an MCP tool definition

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL