A Model Context Protocol (MCP) server for the Linux Foundation's LFX platform, providing tools and resources for interacting with LFX services.
This project implements an MCP server that exposes LFX platform functionality through standardized tools and resources. It's built using the MCP Go SDK and follows the Model Context Protocol specification.
- Hello World Tool: A simple demonstration tool for testing MCP connectivity
- Stdio Transport: Communication via standard input/output streams
- HTTP Transport: Streamable HTTP endpoint for web-based MCP clients
- Extensible Architecture: Clean structure for adding new tools and resources
- Go 1.26.0 or later
- Git
-
Clone the repository:
git clone https://github.com/linuxfoundation/lfx-mcp.git cd lfx-mcp -
Install dependencies:
go mod download
-
Build the server:
go build -o bin/lfx-mcp-server ./cmd/lfx-mcp-server
To start the MCP server with stdio transport (default behavior):
./bin/lfx-mcp-serverThe server will listen for MCP messages on stdin and respond on stdout.
To start the MCP server with HTTP transport:
./bin/lfx-mcp-server -mode=httpThe server will start an HTTP endpoint at http://localhost:8080/mcp that accepts MCP requests over streamable HTTP (Server-Sent Events). This is useful for web-based MCP clients.
The server supports configuration via both command-line flags and environment variables. Environment variables override command-line flags, allowing flags to provide defaults while environment variables can override them in containerized deployments.
Command-line Flags:
-mode: Transport mode:stdioorhttp(default:stdio)-http.port: Port to listen on for HTTP transport (default:8080)-http.host: Host to bind to for HTTP transport (default:127.0.0.1)-http.public_url: Public URL for HTTP transport (for reverse proxies, e.g.,https://example.com/mcp)-debug: Enable debug logging with source location tracking (default:false)-tools: Comma-separated list of tools to enable (default: none)-oauth.domain: Issuer domain for IdP-oauth.resource_url: LFX API domain for OAuth audience-oauth.scopes: OAuth scopes as comma-separated list (default:openid,profile)-token_exchange.token_endpoint: OAuth2 token endpoint URL for RFC 8693 token exchange (e.g.,https://example.auth0.com/oauth/token)-token_exchange.client_id: M2M client ID for token exchange-token_exchange.client_secret: M2M client secret for token exchange (ignored ifclient_assertion_signing_keyis set)-token_exchange.client_assertion_signing_key: PEM-encoded RSA private key for client assertion (RFC 7523). Takes precedence overclient_secretif both are provided-token_exchange.subject_token_type: Subject token type for RFC 8693 (e.g., LFX MCP API identifier)-token_exchange.audience: Target audience for exchanged token (e.g., LFX V2 API identifier)
Environment Variables:
All environment variables use the LFXMCP_ prefix. Variable names use underscores, which are automatically transformed to dots for nested configuration keys (e.g., LFXMCP_HTTP_PORT becomes http.port):
LFXMCP_MODE: Transport mode (stdioorhttp)LFXMCP_HTTP_HOST: HTTP server hostLFXMCP_HTTP_PORT: HTTP server portLFXMCP_DEBUG: Enable debug logging (trueorfalse)LFXMCP_TOOLS: Comma-separated list of tools to enableLFXMCP_MCP_API_AUTH_SERVERS: Comma-separated list of authorization server URLsLFXMCP_MCP_API_PUBLIC_URL: Public URL for MCP API (for OAuth PRM)LFXMCP_MCP_API_SCOPES: OAuth scopes as comma-separated list (default:openid,profile)LFXMCP_CLIENT_ID: OAuth client ID for authenticationLFXMCP_CLIENT_SECRET: OAuth client secretLFXMCP_CLIENT_ASSERTION_SIGNING_KEY: PEM-encoded RSA private key for client assertionLFXMCP_TOKEN_ENDPOINT: OAuth2 token endpoint URL for token exchangeLFXMCP_LFX_API_URL: LFX API URL (used as token exchange audience)
Examples:
With command-line flags:
# Custom HTTP port
./bin/lfx-mcp-server -mode=http -http.port=9090
# Bind to all interfaces
./bin/lfx-mcp-server -mode=http -http.host=0.0.0.0 -http.port=8080With environment variables:
# Start in HTTP mode on custom port
LFXMCP_MODE=http LFXMCP_HTTP_PORT=9090 ./bin/lfx-mcp-server
# Enable debug logging (env var overrides flag)
LFXMCP_DEBUG=true ./bin/lfx-mcp-server
# Environment variable overrides flag
LFXMCP_HTTP_PORT=9090 ./bin/lfx-mcp-server -mode=http -http.port=8080
# Result: Server runs on port 9090 (env var wins)The server uses structured JSON logging via Go's slog package. All logs are written to stdout in JSON format for easy parsing and integration with log aggregation systems.
Log Levels:
INFO(default): Standard operational messagesDEBUG: Detailed diagnostic information with source location tracking
Enabling Debug Logging:
Debug logging can be enabled via command-line flag or environment variable:
# Via command-line flag
./bin/lfx-mcp-server -debug
# Via environment variable
LFXMCP_DEBUG=true ./bin/lfx-mcp-serverWhen debug logging is enabled, the following additional information is included:
- Source file locations for each log statement
- Detailed request/response information
- Internal state transitions
Log Format:
All logs are emitted as JSON objects with the following structure:
{"time":"2024-01-15T10:30:45.123Z","level":"INFO","msg":"Starting HTTP server","addr":"127.0.0.1:8080"}
{"time":"2024-01-15T10:30:45.456Z","level":"ERROR","msg":"server failed","error":"connection refused"}Debug logs include source information:
{"time":"2024-01-15T10:30:45.789Z","level":"DEBUG","source":{"file":"main.go","line":150},"msg":"processing request"}Example HTTP request:
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"web-client","version":"1.0.0"}}}'The HTTP transport uses stateless mode, creating a new MCP session for each request. This allows horizontal scaling without session management.
A simple greeting tool that demonstrates the MCP tool interface.
Parameters:
name(string, optional): Name to greet (defaults to "World")message(string, optional): Custom greeting message
Example usage:
{
"method": "tools/call",
"params": {
"name": "hello_world",
"arguments": {
"name": "LFX User",
"message": "Welcome"
}
}
}lfx-mcp/
├── cmd/
│ └── lfx-mcp-server/ # Main application entry point
├── internal/
│ └── tools/ # MCP tool implementations
├── bin/ # Built binaries (created by make build)
├── go.mod # Go module definition
├── Makefile # Build automation
└── README.md # This file
Tools are implemented in the internal/tools package for better organization and scalability.
-
Create a new file in
internal/tools/(e.g.,my_tool.go):package tools import ( "context" "github.com/modelcontextprotocol/go-sdk/mcp" ) // MyToolArgs defines the input parameters. type MyToolArgs struct { Param1 string `json:"param1" jsonschema:"Description of parameter 1"` Param2 int `json:"param2,omitempty" jsonschema:"Optional parameter 2"` } // RegisterMyTool registers the tool with the MCP server. func RegisterMyTool(server *mcp.Server) { mcp.AddTool(server, &mcp.Tool{ Name: "my_tool", Description: "Description of what the tool does", }, handleMyTool) } // handleMyTool implements the tool logic. func handleMyTool(ctx context.Context, req *mcp.CallToolRequest, args MyToolArgs) (*mcp.CallToolResult, any, error) { // Your tool implementation here return &mcp.CallToolResult{ Content: []mcp.Content{ &mcp.TextContent{Text: "Tool result"}, }, }, nil, nil }
-
Register your tool in
cmd/lfx-mcp-server/main.go:// Register tools. tools.RegisterHelloWorld(server) tools.RegisterMyTool(server) // Add your new tool
To test the server manually, you can send JSON-RPC messages via stdio:
# Test server initialization and tool listing
(echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}';
echo '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}';
sleep 1) | ./bin/lfx-mcp-server
# With debug logging enabled
(echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}';
echo '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}';
sleep 1) | ./bin/lfx-mcp-server -debug
# Test calling the hello_world tool
(echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}';
echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"hello_world","arguments":{"name":"LFX User","message":"Welcome"}}}';
sleep 1) | ./bin/lfx-mcp-serverStart the HTTP server and send requests using curl:
# Start the server in the background
./bin/lfx-mcp-server -mode=http -http.port=8080 &
# Or with debug logging
./bin/lfx-mcp-server -mode=http -http.port=8080 -debug &
# Test tools list
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
# Test calling hello_world tool
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"hello_world","arguments":{"name":"LFX","message":"Welcome"}}}'Responses are returned as Server-Sent Events (SSE) with event: message and data: fields.
Copyright The Linux Foundation and each contributor to LFX.
This project’s source code is licensed under the MIT License. A copy of the license is available in LICENSE.
This project’s documentation is licensed under the Creative Commons Attribution 4.0 International License (CC-BY-4.0). A copy of the license is available in LICENSE-docs.