FastMCP-based MCP Server Orchestrator
Project description
MCP Composer
Table of Contents
- Overview
- Purpose
- Installation
- Development with Makefile
- Usage
- Key Features
- Demo using MCP Inspector
- MCP Composer Client with Chatbot UI
Overview
The MCP Composer is a FastMCP based Composer that manages multiple MCP servers and tools. Servers and tools can be registered at runtime using structured JSON configurations. The MCP Composer serves as an orchestrator for tool execution and forwards tool requests to the correct upstream MCP server or interface.
The MCP Composer supports multiple tool types, such as OpenAPI (REST), GraphQL, CLI-based tools, client SDKs, and nested MCP servers.
Purpose
The goal of the MCP Composer is to handle dynamic tool registration, authentication, invocation dispatching, and health monitoring. It abstracts underlying protocol, authentication and routing complexities, and allows tools to be called through a single, unified interface. The MCP Composer exposes a set of MCP-compliant functions that allow listing tools, invoking them, updating credentials, and removing them.
The goal is to provide a single unified MCP Composer that:
- Discovers and registers new MCP tools on startup or via API.
- Mounts and unmounts member servers dynamically.
- Exposes all tools across registered servers.
Installation
Update the pyproject.toml if you need to install both mcp_composer and mcp_composer_app
[tool.setuptools.packages.find]
where = ["src"]
include = ["mcp_composer", "mcp_composer_app"]
If we only want to install mcp_composer
[tool.setuptools.packages.find]
where = ["src"]
include = ["mcp_composer"]
For multiple installation methods, please refer to the Installation Guide
Prerequisites
- Python 3.10+
- uv (Recommended for environment management)
Setup
-
Clone the repository
git clone https://github.com/IBM/mcp-composer.git cd mcp-composer
-
Create virtual Environment:
uv venv
-
Activate the virtual environment.
source .venv/bin/activate
-
Environment Configuration (Required)
The MCP Composer requires environment variables to be set:
Setup
cp env.example .env
Edit the
.envfile and set the required environment variables:SERVER_CONFIG_FILE_PATH: Path to the server configuration file (default:member_servers.json)
Note: If you don't set up the
.envfile, you'll get aKeyError: 'SERVER_CONFIG_FILE_PATH'error when trying to import the module. -
Database Configuration (Optional)
The MCP Composer supports multiple database backends for storing server configurations, tools, prompts, and resources:
Default Behavior: If no database configuration is provided, MCP Composer runs without persistent storage (no database).
Environment Variable Configuration (Recommended):
You can configure the database using environment variables, which take priority over programmatic configuration:
# For Cloudant database export MCP_DATABASE_TYPE="cloudant" export MCP_DATABASE_API_KEY="your_cloudant_api_key" export MCP_DATABASE_SERVICE_URL="https://your-cloudant-instance.cloudantnosqldb.appdomain.cloud" export MCP_DATABASE_DB_NAME="mcp_servers" # Optional, defaults to "mcp_servers" # For local file storage export MCP_DATABASE_TYPE="local_file" export MCP_DATABASE_FILE_PATH="/path/to/your/servers.json" # Optional # Enable local file storage when no other database config is provided export MCP_USE_LOCAL_FILE_STORAGE="true"
MCP_DATABASE_TYPE: Database type ("cloudant"or"local_file")MCP_DATABASE_API_KEY: API key for Cloudant (required for cloudant type)MCP_DATABASE_SERVICE_URL: Service URL for Cloudant (required for cloudant type)MCP_DATABASE_DB_NAME: Database name (optional, defaults to"mcp_servers")MCP_DATABASE_FILE_PATH: File path for local storage (optional for local_file type)MCP_USE_LOCAL_FILE_STORAGE: Set to"true"to enable local file storage when no other config is provided
Programmatic Database Configuration:
You can also provide a
database_configdictionary when initializing MCPComposer:from mcp_composer import MCPComposer # Cloudant configuration database_config = { "type": "cloudant", "api_key": "your_cloudant_api_key", "service_url": "https://your-cloudant-instance.cloudantnosqldb.appdomain.cloud", "db_name": "mcp_servers" # Optional, defaults to "mcp_servers" } composer = MCPComposer( name="my-composer", database_config=database_config )
Local File Storage Configuration:
from mcp_composer import MCPComposer # Local file storage configuration database_config = { "type": "local_file", "file_path": "/path/to/your/servers.json" # Optional } composer = MCPComposer( name="my-composer", database_config=database_config )
Required Cloudant Parameters:
type: Must be set to"cloudant"api_key: Your IBM Cloudant API keyservice_url: Your Cloudant service URL (must start withhttp://orhttps://)
Optional Cloudant Parameters:
db_name: Database name (defaults to"mcp_servers")
Custom Database Interface:
You can also provide a custom database implementation by passing a
DatabaseInterfaceinstance:from mcp_composer.store.database import DatabaseInterface class MyCustomDatabase(DatabaseInterface): # Implement required methods pass custom_db = MyCustomDatabase() composer = MCPComposer( name="my-composer", database_config=custom_db )
Configuration Priority:
- Environment variables (highest priority)
- Programmatic configuration
- No database (default behavior)
Error Handling: If database configuration is provided but missing required keys or has invalid values, the composer will log warnings and fall back to no database configuration.
-
Synchronize the environment.
First time setup: Run this to create the initial
uv.lockfile:uv syncSubsequent runs: Use the frozen lock file for consistency:
uv sync --frozen # Strict install (uses lock file exactly) - recommended as ensuring consistency across different environments
Update dependencies: If you need to update dependencies:
rm uv.lock && uv sync # Refresh child dependencies, commit uv.lock
-
Add a new dependency; automatically creates a virtual environment if necessary
uv add <my-package>
-
Leverage the project's virtual environment:
uv run <command&args> -
Test if MCP Composer is installed successfully or not
uv run python -c "import mcp_composer; print(mcp_composer.__version__)"
Add MCP Composer as local dependency
- Update the
pyproject.tomlwith the following:
[tool.hatch.metadata]
allow-direct-references = true
Then you can run the command:
uv add <path to mcp-composer folder>
Then, the pyproject.toml file is updated with the below lines:
[tool.uv.sources]
mcp-composer = { path = "mcp-composer" }
Add mcp-composer to the dependencies section, example of the final pyproject.toml file:
[project]
name = "py_project"
[tool.hatch.metadata]
allow-direct-references = true
dependencies = [
"mcp-composer",
... ...
]
[tool.uv.sources]
mcp-composer= { path = "mcp-composer" }
To ensure the package is properly installed and importable in the consumer project, the following command must be run manually:
uv pip install -e ../mcp-composer
Use as Tool
Install mcp-composer as a tool
-
Run the following command to install mcp-composer as a tool:
uv tool install -e /<absolute path>/mcp-composer
-
Add the tool to $PATH:
export PATH="/<absolute path>/.local/bin:$PATH"
-
Check the installation:
which mcp-composer
Uninstall mcp-composer as a tool
-
Run the following command to uninstall mcp-composer as a tool:
uv tool uninstall mcp-composer
Development with Makefile
The MCP Composer project includes a comprehensive Makefile that provides convenient commands for development tasks, quality assurance, and package management.
Quick Start
Run all quality assurance checks in sequence:
make all
Development Tasks
Code Quality
make format- Format code with blackmake lint- Lint code with ruffmake type-check- Run type checks with mypymake test- Run tests with coveragemake coverage- Generate coverage reportmake check- Run all checks in sequence
Module Testing
make test-module module=<module_name>- Run unit tests for a specific modulemake test-modules- Run unit tests for all modules
Cleanup
make clean- Clean up generated files and caches
PyPI Release Management
Build and Release
make build module=<module_name> version=<x.y.z>- Build wheel for a specific modulemake check-release module=<module_name> version=<x.y.z>- Verify wheel with twinemake upload-testpypi module=<module_name> version=<x.y.z>- Upload to TestPyPImake upload-pypi module=<module_name> version=<x.y.z>- Upload to PyPI
Environment Status
make status- Show environment status for releases
Examples
# Run all QA checks
make all
# Test a specific module
make test-module module=mcp_composer
# Build a module for release
make build module=mcp_composer version=1.0.0
# Check release artifacts
make check-release module=mcp_composer version=1.0.0
# Upload to TestPyPI
make upload-testpypi module=mcp_composer version=1.0.0
# Clean up development artifacts
make clean
Prerequisites for Releases
For PyPI uploads, you'll need to set environment variables:
# For TestPyPI
export TEST_TWINE_USERNAME="your_test_username"
export TEST_TWINE_PASSWORD="your_test_password"
# For PyPI
export TWINE_USERNAME="your_username"
export TWINE_PASSWORD="your_p assword"
For more detailed information about available commands, run:
make help
Usage
- Run MCP Server using MCP Composer Tool with oauth authentication with following command
uvx mcp-composer -sseurl --sse-url <url to remote sse mcp server> --auth_type oauth --env OAUTH_HOST <host> --env OAUTH_PORT <port> --env OAUTH_SERVER_URL <server url> --env OAUTH_CALLBACK_PATH <callback path> --env OAUTH_CLIENT_ID=<client id> --env OAUTH_CLIENT_SECRET <secret> --env OAUTH_AUTH_URL <auth url> -e-env OAUTH_TOKEN_URL <token url> --env OAUTH_MCP_SCOPE user --env OAUTH_PROVIDER_SCOPE=openid
Key Features
- Register or remove tools at runtime using structured JSON configurations.
- Support a range of tool types (openapi, graphql, client, mcp, etc.)
- Handles multiple authentication strategies.
- Automatically forwards each request to the correct upstream server or tool.
- List tools and metadata by name or server.
- Database Support: Configurable database backends including IBM Cloudant and local file storage for persistent server configurations, tools, prompts, and resources.
- Environment Variable Configuration: Database configuration through environment variables with validation and fallback support.
- Database Configuration Validation: Strict validation of database configuration with fail-fast behavior to prevent startup with invalid database settings.
MCP Composer Servers
Add MCP Server from local python file in stdio
To add an MCP server from a local python file, use the builder with a configuration containing the python file path:
Example:
[
{
"id": "mcp-local-news",
"type": "stdio",
"command": "uv",
"args": [
"--directory",
"/<absolute path of the directory>",
"run",
"<name of the python file>.py"
],
"_id": "mcp-local-news"
}
]
Run
uv run test/test_composer.py
test_composer.py can run on either stdio or http type.
This will create a FastMCP server instance using the python file and its dependencies and also mount it on mcp-composer.
Add MCP Server from OpenAPI Specification
To add an MCP server from an OpenAPI spec, use the builder with a configuration containing the OpenAPI details:
Example:
from mcp_composer.member_servers.builder import MCPServerBuilder
config = {
"id": "my-openapi-server",
"type": "openapi",
"open_api": {
"endpoint": "https://api.example.com",
"spec_url": "https://api.example.com/openapi.json",
# Optional: "custom_routes": "path/to/custom_routes.json"
},
"auth_strategy": "bearer",
"auth": {
"token": "your-token"
}
}
builder = MCPServerBuilder(config)
mcp_server = await builder.build()
This will create a FastMCP server instance using the OpenAPI specification and authentication details provided.
Add MCP Server from GraphQL Schema
To add an MCP server from a GraphQL schema, use the builder with a configuration containing the GraphQL endpoint:
Example:
from mcp_composer.member_servers.builder import MCPServerBuilder
config = {
"id": "my-graphql-server",
"type": "graphql",
"endpoint": "https://graphql.example.com/graphql",
# Add any other required config options
}
builder = MCPServerBuilder(config)
mcp_server = await builder.build()
This will create a FastMCP server instance with a GraphQL tool registered, allowing you to interact with the GraphQL API through MCP Composer.
Database Configuration for Server Management
When initializing MCPComposer, you can configure the database backend for persistent storage of server configurations:
Example with Environment Variables (Recommended):
# Set environment variables
export MCP_DATABASE_TYPE="cloudant"
export MCP_DATABASE_API_KEY="your_cloudant_api_key"
export MCP_DATABASE_SERVICE_URL="https://your-cloudant-instance.cloudantnosqldb.appdomain.cloud"
export MCP_DATABASE_DB_NAME="mcp_servers"
from mcp_composer import MCPComposer
# Initialize composer - database config will be loaded from environment variables
composer = MCPComposer(name="my-composer")
# Server configurations will be automatically persisted to Cloudant
await composer.setup_member_servers()
Example with Programmatic Cloudant Configuration:
from mcp_composer import MCPComposer
# Configure Cloudant database programmatically
database_config = {
"type": "cloudant",
"api_key": "your_cloudant_api_key",
"service_url": "https://your-cloudant-instance.cloudantnosqldb.appdomain.cloud",
"db_name": "mcp_servers" # Optional
}
# Initialize composer with database configuration
composer = MCPComposer(
name="my-composer",
database_config=database_config
)
# Server configurations will be automatically persisted to Cloudant
await composer.setup_member_servers()
Example with Local File Storage:
# Option 1: Using environment variables
export MCP_DATABASE_TYPE="local_file"
export MCP_DATABASE_FILE_PATH="/path/to/servers.json"
# Option 2: Enable local file storage when no other config is provided
export MCP_USE_LOCAL_FILE_STORAGE="true"
from mcp_composer import MCPComposer
# Option 1: Environment variables will be used automatically
composer = MCPComposer(name="my-composer")
# Option 2: Programmatic configuration
database_config = {
"type": "local_file",
"file_path": "/path/to/servers.json" # Optional
}
composer = MCPComposer(
name="my-composer",
database_config=database_config
)
# Server configurations will be stored locally
await composer.setup_member_servers()
Example with No Database (Default):
from mcp_composer import MCPComposer
# No database configuration - runs without persistent storage
composer = MCPComposer(name="my-composer")
# Server configurations will not be persisted
await composer.setup_member_servers()
Benefits of Database Configuration:
- Persistence: Server configurations, tools, prompts, and resources are saved across restarts
- Scalability: Cloudant provides distributed storage for multi-instance deployments
- Management: Tools for enabling/disabling tools, prompts, and resources per server
- Versioning: Support for configuration versioning and rollback capabilities
Command Line Interface (CLI)
MCP Composer can now be launched directly via a CLI using the mcp-composer entry point. This provides a lightweight and flexible way to spin up the composer using either HTTP or stdio mode.
Usage
mcp-composer --mode <http|stdio> [--host HOST] [--port PORT] [--log-level LEVEL] [--path PATH] [--config <config.json>]
Options
| Flag | Description | Default |
|---|---|---|
--mode |
Mode to run the Composer in: http or stdio |
http |
--host |
Host to bind to (for http mode) |
0.0.0.0 |
--port |
Port to run on (for http mode) |
9000 |
--log-level |
Log level (e.g. debug, info, warning) |
debug |
--path |
URL path to mount the MCP Composer on | /mcp |
MCP Composer Tools
Server Management Tools
register_mcp_server: Register a single server.delete_mcp_server: Delete a single server.member_health: Get status for all member servers.activate_mcp_server: Reactivates a previously deactivated member server by loading its config, updating status in DB, and mounting it.deactivate_mcp_server: Deactivates a member server by unmounting it and marking it as deactivated in DB.list_member_servers: List status of all member servers (active or deactivated).
Tool Management Tools
get_tool_config_by_name: Get a tool configuration detailsget_tool_config_by_server: Get all tool configuration details of a specific member serverdisable_tools: Disable a tool or multiple from the servers and Composerenable_tools: Enable a tool or multiple from the servers and Composerupdate_tool_description: Update tool description of member servers- add_tools: Add tool using curl command or Python script.
- add_tools_from_openapi: Add tool using the OpenAPI specifications
Prompt Management Tools
add_prompts: Add one or more prompts to the composerget_all_prompts: Get all registered prompts as JSON strings (excluding disabled ones)list_prompts_per_server: List all prompts from a specific server (excluding disabled ones)filter_prompts: Filter prompts based on criteria like name, description, tagsenable_prompts: Enable prompts from a specific serverdisable_prompts: Disable prompts from a specific server
Resource Management Tools
add_resource_template: Add a resource template to the composercreate_resource: Create a new resource in the composerlist_resources: List all available resources (actual resources)list_resource_templates: List all available resource templateslist_resources_per_server: List all resources and templates from a specific serverfilter_resources: Filter resources based on criteria like name, description, tagsenable_resources: Enable resources or templates from a specific serverdisable_resources: Disable resources or templates from a specific server
Add tool using Curl command and Python script
Curl command:
{
"name": "event",
"tool_type": "curl",
"curl_config": {
"value": "curl 'https://www.eventbriteapi.com/v3/users/me/organizations/' --header 'Authorization: Bearer XXXXXXXX'"
},
"description": "sample test",
"permission": {
"role 1": "permission 1 "
}
}
Python script:
{
"name": "test",
"tool_type": "script",
"script_config": {
"value": "def search_news(keyword: str) -> str:\n '''Simulate news search using a ticker and return top articles.'''\n import yfinance as yf\n import json\n stock = yf.Ticker(keyword.upper())\n news = stock.news[:5]\n result = []\n for article in news:\n result.append({\n 'title': article.get('title'),\n 'publisher': article.get('publisher'),\n 'link': article.get('link'),\n 'providerPublishTime': article.get('providerPublishTime'),\n })\n return json.dumps(result, indent=2)"
},
"description": "Search top 5 news articles related to a stock ticker using yfinance.",
"permission": {
"role 1": "permission 1"
}
}
Add tool using OpenAPI specification
input: openapi_spec
{
"openapi": "3.0.1",
"info": {
"title": "IBM Concert API v1.1.0",
"version": "1.1.0",
...
...
}
}
input: auth_config
{
"auth_strategy": "basic",
"auth": {
"username": "user1",
"password": "xxxxxxxx"
}
}
MCP Composer Prompts
Adding one or more prompts
-
add_prompts(prompt_config: list[dict]) -> list[str]Registers one or more prompts with the composer. -
Arguments:
prompt_config: A list of dictionaries, each describing a prompt. Each dictionary should contain at least aname,description, andtemplatefield.
-
Returns: A list of registered prompt names.
Example:
prompt_config = [
{
"name": "promo_http_avg_response",
"description": "Average response time of promo HTTP calls handled by a cluster",
"template": "What is the average response time of promo HTTP calls handled by Kubernetes cluster {{ cluster }}?",
"arguments": [
{
"name": "cluster",
"type": "string",
"required": true,
"description": "The name of the Kubernetes cluster"
}
]
}
]
added = await composer.add_prompts(prompt_config)
Get all Prompts
-
get_all_prompts() -> list[str]Retrieves all registered prompts as JSON strings, with internal function references stripped. -
Returns: A list of JSON strings, each representing a prompt (excluding the
fnfield).
Example:
prompts = await composer.get_all_prompts()
for prompt_json in prompts:
print(prompt_json)
List Prompts per Server
-
list_prompts_per_server(server_id: str) -> list[dict]Lists all prompts from a specific server (excluding disabled ones). -
Arguments:
server_id: The ID of the server to list prompts from.
-
Returns: A list of dictionaries containing prompt information with server_id included.
Example:
prompts = await composer.list_prompts_per_server("my-server")
for prompt in prompts:
print(f"Prompt: {prompt['name']} from server: {prompt['server_id']}")
print(f" Description: {prompt['description']}")
print(f" Template: {prompt['template']}")
Enable Prompts
-
enable_prompts(prompts: list[str], server_id: str) -> strEnables prompts from a specific server. -
Arguments:
prompts: A list of prompt names to enable.server_id: The ID of the server containing the prompts.
-
Returns: A status message indicating success or failure.
Example:
result = await composer.enable_prompts(["app_top_errors_yesterday"], "mcp-prompt")
print(result) # "Enabled ['mcp-prompt_app_top_errors_yesterday'] prompts from server mcp-prompt"
Disable Prompts
-
disable_prompts(prompts: list[str], server_id: str) -> strDisables prompts from a specific server. -
Arguments:
prompts: A list of prompt names to disable.server_id: The ID of the server containing the prompts.
-
Returns: A status message indicating success or failure.
Example:
result = await composer.disable_prompts(["app_top_errors_yesterday"], "mcp-prompt")
print(result) # "Disabled ['mcp-prompt_app_top_errors_yesterday'] prompts from server mcp-prompt"
Filter Prompts
-
filter_prompts(filter_criteria: dict) -> list[dict]Filters prompts based on criteria like name, description, tags, etc. -
Arguments:
filter_criteria: A dictionary containing filter criteria (name, description, tags).
-
Returns: A list of dictionaries containing matching prompts.
Example:
# Filter by name
result = await composer.filter_prompts({"name": "test"})
# Filter by description
result = await composer.filter_prompts({"description": "response"})
# Filter by multiple criteria
result = await composer.filter_prompts({
"name": "prompt",
"description": "test"
})
MCP Composer Resources
Adding resource templates
-
add_resource_template(resource_config: dict) -> strRegisters a resource template with the composer. -
Arguments:
resource_config: A dictionary describing the resource template. Should contain at least anamefield.
-
Returns: A success message.
Example:
resource_config = {
"name": "my_template",
"description": "A template for creating resources",
"uri_template": "resource://{name}",
"mime_type": "text/plain",
"tags": ["template", "example"],
"enabled": True
}
result = await composer.add_resource_template(resource_config)
Creating actual resources
-
create_resource(resource_config: dict) -> strCreates an actual resource in the composer. -
Arguments:
resource_config: A dictionary describing the resource. Should contain at least anamefield.
-
Returns: A success message.
Example:
resource_config = {
"name": "my_resource",
"description": "An actual resource with content",
"uri": "resource://my_resource",
"mime_type": "text/plain",
"content": "This is the actual content of the resource",
"tags": ["resource", "example"],
"enabled": True
}
result = await composer.create_resource(resource_config)
Listing resources and templates
-
list_resources() -> list[dict]Lists all actual resources from composer and mounted servers. -
list_resource_templates() -> list[dict]Lists all resource templates from composer and mounted servers.
Example:
# List actual resources
resources = await composer.list_resources()
for resource in resources:
print(f"Resource: {resource['name']} - {resource['description']}")
# List resource templates
templates = await composer.list_resource_templates()
for template in templates:
print(f"Template: {template['name']} - {template['description']}")
List Resources per Server
-
list_resources_per_server(server_id: str) -> list[dict]Lists all resources and templates from a specific server. -
Arguments:
server_id: The ID of the server to list resources from.
-
Returns: A list of dictionaries containing resource information with server_id and type included.
Example:
resources = await composer.list_resources_per_server("my-server")
for resource in resources:
print(f"Resource: {resource['name']} from server: {resource['server_id']}")
print(f" Type: {resource['type']}") # 'resource' or 'template'
Enable Resources
-
enable_resources(resources: list[str], server_id: str) -> strEnables resources or templates from a specific server. -
Arguments:
resources: A list of resource names to enable.server_id: The ID of the server containing the resources.
-
Returns: A status message indicating success or failure.
Example:
result = await composer.enable_resources(["finance_reference"], "mcp-stock-info")
print(result) # "Enabled ['mcp-stock-info_finance_reference'] resources/templates from server mcp-stock-info"
Disable Resources
-
disable_resources(resources: list[str], server_id: str) -> strDisables resources or templates from a specific server. -
Arguments:
resources: A list of resource names to disable.server_id: The ID of the server containing the resources.
-
Returns: A status message indicating success or failure.
Example:
result = await composer.disable_resources(["finance_reference"], "mcp-stock-info")
print(result) # "Disabled ['mcp-stock-info_finance_reference'] resources/templates from server mcp-stock-info"
Filter Resources
-
filter_resources(filter_criteria: dict) -> list[dict]Filters resources based on criteria like name, description, tags, etc. -
Arguments:
filter_criteria: A dictionary containing filter criteria (name, description, tags, type).
-
Returns: A list of dictionaries containing matching resources.
Example:
# Filter by name
result = await composer.filter_resources({"name": "resource"})
# Filter by description
result = await composer.filter_resources({"description": "test"})
# Filter by type (resource or template)
result = await composer.filter_resources({"type": "resource"})
# Filter by multiple criteria
result = await composer.filter_resources({
"name": "resource",
"description": "test",
"type": "template"
})
Demo using MCP Inspector
-
Run the MCP Inspector as a background process, and take note of the session token/url with token pre-filled:
npx @modelcontextprotocol/inspectorTo run a specific version use the following command
npx @modelcontextprotocol/inspector@0.14.3 -
Navigate to
mcp-composer/and create a.envfile by copying the contents of.env.example.Then, set the Server and Tool config path in env file accordingly:cp mcp-composer/.env.example mcp-composer/.env
-
Run the following command
uv run test/test_composer.py
-
Open the MCP Inspector in a browser with token pre-filled from the first step above. You can also open on
localhost:6274and provide thetokenfrom the first step as theProxy Session Token. -
set transport type and URL from the previous step above and press
Connect: -
Go to Tools in the MCP Inspector and List Tools:
-
We will first use the
register_mcp_servertool and registerstock_infoMCP server using the bellow config:{ "id": "mcp-stock-info", "type": "http", "endpoint": "https://mcp-stock-info.1vgzmntiwjzl.eu-es.codeengine.appdomain.cloud/mcp" }
-
Once the tool is run, it will be successfully registered:
-
Clear Tool and List Tool again - This is where it might take long time or throw time out error based on the configuration of the MCP Inspector. In case you have time out error disconnect the server and connect again and run the List Tool, it will show all the tools from composer and all tools from
mcp-stockinfo: -
Run any tools:
Demo: OAuth
1. Create the environment file
Navigate to mcp-composer and create a .env file by copying the contents of .env.example:
cp mcp-composer/.env.example mcp-composer/.env
2. Configure OAuth credentials
Open .env and replace the placeholder values with your actual OAuth provider details (e.g., client ID, client secret, redirect URI, etc.).
3. Run the MCP Composer server
Execute the following command to start the server and test the OAuth integration:
uv run test/test_composer_oauth.py
MCP Composer Client with Chatbot UI
MCP composer client provides an agent backend service to provide chatbot service that talks with all the tools from MCP Composer server.
A chatbot UI demo is also provided just for testing purpose Demo-Chatbot-UI.
1. Setup env variables and configuration
In the same .env (copied from mcp-composer/.env.example), setup the following variables:
CHAT_MODEL_NAME: watsonx or ollamaWATSONX_CHAT_MODEL: meta-llama/llama-4-maverick-17b-128e-instruct-fp8, ibm/granite-3-3-8b-instruct, etcWATSONX_URL: Watsonx Instance URLWATSONX_API_KEY: API-Key of Watsonx instanceWATSONX_PROJECT_ID: Watsonx Project IDCHAT_MODEL_NAME: local ollama model (ifCHAT_MODEL_NAME=ollama)
Config file config/mcp_composer_client.yaml defines what MCP servers are connected, at current stage, it supports:
- Remote MCP-Composer Server
- Remote SSE/Http MCP-Server (testing purpose)
- Stdio MCP-Server (testing purpose)
Each server config has a boolean field enabled to enable the server or disable it.
2. Launch chatbot agent service
(Before running chatbot agent service, make sure all enabled: true server in config/mcp_composer_client.yaml is properly setup and can be connected.)
- Option-1. Run agent service in local development environment
Launch agent service:
uv run src/mcp_composer_client/acp_server.py
It should output agent server URL in terminal:
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://localhost:8000 (Press CTRL+C to quit)
-
Option-2. Build and Run Docker Image
Build the image, taking default tag as "chatbot":
docker build -t chatbot -f Dockerfile_Client .
Run the image in container interactively (for Windows/Mac), by default, it uses
MCP_BASE_URLto connect to MCP composer server.docker run -it -e HOST=0.0.0.0 -p 8000:8000 chatbot
(In Linux,
-e HOST=0.0.0.0can be removed.)If using
config/mcp_composer_client.yamlto config multiple MCP servers, set envUSER_CONFIG_FILEtoyes:docker run -it -e USER_CONFIG_FILE=yes -e HOST=0.0.0.0 -p 8000:8000 chatbot
3. Launch chatbot UI (Optional)
Follow instruction in Demo-Chatbot-UI, open browser and input chatbot UI URL. Interact with the chatbot.
Troubleshooting
Common Issues
-
KeyError: 'SERVER_CONFIG_FILE_PATH'- Cause: Missing environment variable configuration
- Solution: Copy
env.exampleto.envand set the required environment variables
cp env.example .env
-
error: Unable to find lockfile at uv.lock- Cause: Missing lock file (first-time setup)
- Solution: Run
uv syncfirst to create the initial lock file
uv sync -
Import errors when testing installation
- Cause: Environment variables not loaded
- Solution: Ensure
.envfile exists and contains required variables
# Check if .env file exists ls -la .env # If not, create it cp env.example .env
-
Package not found when adding as local dependency
- Cause: Path issues or missing development install
- Solution: Use the full path and install in editable mode
uv add /full/path/to/mcp-composer --frozen uv pip install -e /full/path/to/mcp-composer
-
Database configuration not working
- Cause: Invalid environment variables or missing required parameters
- Solution: Check environment variable format and required parameters
# Check environment variables echo $MCP_DATABASE_TYPE echo $MCP_DATABASE_API_KEY echo $MCP_DATABASE_SERVICE_URL # For Cloudant, ensure URL starts with http:// or https:// export MCP_DATABASE_SERVICE_URL="https://your-instance.cloudantnosqldb.appdomain.cloud" # For local file storage, ensure file path is valid export MCP_DATABASE_FILE_PATH="/path/to/valid/file.json"
-
Environment variables not taking effect
- Cause: Environment variables not properly set or loaded
- Solution: Ensure environment variables are set before running the application
# Set environment variables in your shell export MCP_DATABASE_TYPE="cloudant" export MCP_DATABASE_API_KEY="your_key" export MCP_DATABASE_SERVICE_URL="https://your-instance.cloudantnosqldb.appdomain.cloud" # Or add them to your .env file echo "MCP_DATABASE_TYPE=cloudant" >> .env echo "MCP_DATABASE_API_KEY=your_key" >> .env echo "MCP_DATABASE_SERVICE_URL=https://your-instance.cloudantnosqldb.appdomain.cloud" >> .env
-
Server fails to start with database configuration errors
- Cause: Invalid database configuration (missing required fields, invalid URLs, etc.)
- Solution: Fix the database configuration errors
# Check the error logs for specific database configuration issues # Common issues: missing API keys, invalid service URLs, unsupported database types # For Cloudant, ensure all required fields are set: export MCP_DATABASE_TYPE="cloudant" export MCP_DATABASE_API_KEY="your_valid_api_key" export MCP_DATABASE_SERVICE_URL="https://your-instance.cloudantnosqldb.appdomain.cloud" # For local file storage: export MCP_DATABASE_TYPE="local_file" export MCP_DATABASE_FILE_PATH="/path/to/valid/file.json"
-
Server starts but some servers are not mounted
- Cause: Individual server configuration errors (unsupported types, invalid endpoints, etc.)
- Solution: Check logs for mount errors and fix the problematic server configurations
# Look for "Failed to mount server" messages in the logs # Fix the specific server configurations that are failing # Server will continue to run with successfully mounted servers
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file iflow_mcp_ibm_mcp_composer-0.1.0.9.tar.gz.
File metadata
- Download URL: iflow_mcp_ibm_mcp_composer-0.1.0.9.tar.gz
- Upload date:
- Size: 250.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
511907393340e461ad4e8aeb9e75860b71d10913b41cc93160a413096c8cf78a
|
|
| MD5 |
363715dc8ea5ed2f84e432e16a5b71aa
|
|
| BLAKE2b-256 |
2b36104a1c6ced70f88edbcb712311db99c1ff25e58ac346766b278fc0172ce5
|
File details
Details for the file iflow_mcp_ibm_mcp_composer-0.1.0.9-py3-none-any.whl.
File metadata
- Download URL: iflow_mcp_ibm_mcp_composer-0.1.0.9-py3-none-any.whl
- Upload date:
- Size: 17.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5e5f4c7cfb56b4eefeac1364cad705db50f2385fe6029ffce7e4778013add40e
|
|
| MD5 |
e789a060020f5d0533e9948cff9848b4
|
|
| BLAKE2b-256 |
37fa69b32bbf0c7beb134d9075b11a082201d57c676c6bf24405745a9c649364
|