If you find this package useful, consider supporting ongoing development on PayPal.

mcp_bundle: Bundle schema, loader, validator, expression language, and port contracts for MCP ecosystem.mcp_fact_graph: Temporal knowledge graph with evidence-based fact management and summarization.mcp_skill: Skill definitions and runtime execution for AI capabilities.mcp_profile: Profile definitions for AI personas with template rendering and appraisal.mcp_knowledge_ops: Knowledge operations including pipelines, workflows, and scheduling.mcp_knowledge: Unified integration package for the complete knowledge system.
A foundational Dart package providing bundle schema definitions, loading, validation, expression language, and port contracts for the MCP ecosystem. This is the core package that other MCP packages depend on.
- Bundle Schema: Define and structure MCP bundles with skills, profiles, and knowledge
- Bundle Loader: Load bundles from files, URLs, or raw data
- Bundle Validator: Validate bundle structure and content
- Expression Language: Powerful expression evaluation for dynamic content
- Port Contracts: Universal interfaces for LLM, Storage, Metrics, Events, and Channels
- LlmPort: LLM completion interface
- StoragePort: Key-value and document storage
- MetricPort: Metrics and telemetry
- EventPort: Event publishing and subscription
- ChannelPort: Bidirectional channel communication (Slack, Telegram, Discord, HTTP, WebSocket)
- Skills: Skill definitions within bundles
- Profiles: Profile definitions within bundles
- Knowledge: Knowledge items within bundles
- Metadata: Bundle versioning and metadata
- Variable Access:
{{variable}}syntax - Conditionals:
{{#condition}}...{{/condition}} - Loops:
{{#array}}...{{/array}} - Functions: Built-in functions for data manipulation
Add to your pubspec.yaml:
dependencies:
mcp_bundle: ^0.2.0import 'package:mcp_bundle/mcp_bundle.dart';
void main() async {
// Create a bundle
final bundle = McpBundle(
id: 'my_bundle',
name: 'My AI Bundle',
version: '1.0.0',
skills: [
BundleSkill(
id: 'summarizer',
name: 'Text Summarizer',
description: 'Summarizes text content',
executor: 'llm',
prompt: 'Summarize: {{input.text}}',
),
],
profiles: [
BundleProfile(
id: 'assistant',
name: 'Helpful Assistant',
systemPrompt: 'You are a helpful assistant for {{user.name}}.',
),
],
);
// Validate bundle
final validator = BundleValidator();
final validation = await validator.validate(bundle);
if (validation.isValid) {
print('Bundle is valid!');
} else {
print('Errors: ${validation.errors}');
}
// Save bundle
final loader = BundleLoader();
await loader.save(bundle, 'my_bundle.mcpb');
}The Channel Port provides a universal bidirectional communication interface for messaging platforms.
import 'package:mcp_bundle/ports.dart';
// Channel Identity - identifies a platform
final identity = ChannelIdentity(
platform: 'slack', // slack, telegram, discord, http, websocket
channelId: 'T123456', // workspace ID, server ID, etc.
displayName: 'My Workspace',
);
// Conversation Key - unique conversation identifier
final conversation = ConversationKey(
channel: identity,
conversationId: 'C789', // channel, thread, or DM ID
userId: 'U123', // optional user context
);
// Channel Event - incoming event
final event = ChannelEvent.message(
id: 'evt_123',
conversation: conversation,
text: 'Hello, bot!',
userId: 'U123',
userName: 'John Doe',
);
// Channel Response - outgoing message
final response = ChannelResponse.text(
conversation: conversation,
text: 'Hi there! How can I help?',
replyTo: event.id,
);
// Rich response with blocks (Slack, Discord)
final richResponse = ChannelResponse.rich(
conversation: conversation,
blocks: [
{'type': 'section', 'text': {'type': 'mrkdwn', 'text': '*Hello!*'}},
],
text: 'Hello!', // fallback text
);// Check what features a channel supports
final capabilities = ChannelCapabilities(
text: true,
richMessages: true,
attachments: true,
reactions: true,
threads: true,
editing: true,
deleting: true,
typingIndicator: true,
maxMessageLength: 4000,
);
// Presets
final fullCapabilities = ChannelCapabilities.full();
final textOnly = ChannelCapabilities.textOnly();import 'package:mcp_bundle/ports.dart';
class MyChannelPort implements ChannelPort {
final _eventController = StreamController<ChannelEvent>.broadcast();
@override
ChannelIdentity get identity => ChannelIdentity(
platform: 'my-platform',
channelId: 'channel-1',
);
@override
ChannelCapabilities get capabilities => ChannelCapabilities.textOnly();
@override
Stream<ChannelEvent> get events => _eventController.stream;
@override
Future<void> start() async {
// Start receiving events
}
@override
Future<void> stop() async {
await _eventController.close();
}
@override
Future<void> send(ChannelResponse response) async {
// Send message to platform
}
@override
Future<void> sendTyping(ConversationKey conversation) async {
// Show typing indicator
}
@override
Future<void> edit(String messageId, ChannelResponse response) async {
// Edit existing message
}
@override
Future<void> delete(String messageId) async {
// Delete message
}
@override
Future<void> react(String messageId, String reaction) async {
// Add reaction to message
}
}// StubChannelPort for unit testing
final stub = StubChannelPort();
await stub.start();
// Simulate incoming event
stub.simulateEvent(ChannelEvent.message(
id: 'test-1',
conversation: testConversation,
text: 'Test message',
));
// Check sent responses
expect(stub.sentResponses, hasLength(1));
// EchoChannelPort echoes messages back
final echo = EchoChannelPort();
await echo.start();
echo.events.listen((event) {
print('Received: ${event.text}'); // "Echo: Hello"
});
await echo.send(ChannelResponse.text(
conversation: testConversation,
text: 'Hello',
));The main bundle container:
final bundle = McpBundle(
id: 'customer_service',
name: 'Customer Service AI',
version: '2.0.0',
description: 'AI capabilities for customer service',
skills: [...],
profiles: [...],
knowledge: [...],
metadata: {
'author': 'MakeMind',
'category': 'customer-service',
},
);Load and save bundles:
final loader = BundleLoader();
// Load from file
final bundle = await loader.load('path/to/bundle.mcpb');
// Load from URL
final remoteBundle = await loader.loadFromUrl('https://example.com/bundle.mcpb');
// Load from raw data
final dataBundle = await loader.loadFromJson(jsonData);
// Save bundle
await loader.save(bundle, 'output.mcpb');Validate bundle structure and content:
final validator = BundleValidator();
final validation = await validator.validate(bundle);
print('Valid: ${validation.isValid}');
print('Errors: ${validation.errors}');
print('Warnings: ${validation.warnings}');
// Validate specific parts
final skillValidation = await validator.validateSkills(bundle.skills);
final profileValidation = await validator.validateProfiles(bundle.profiles);Evaluate expressions with context:
final expression = ExpressionEvaluator();
// Simple variable access
final result = expression.evaluate(
'{{user.name}}',
{'user': {'name': 'John'}},
);
// Result: 'John'
// Conditional sections
final conditional = expression.evaluate(
'{{#isPremium}}Premium features enabled{{/isPremium}}',
{'isPremium': true},
);
// Result: 'Premium features enabled'
// Array iteration
final loop = expression.evaluate(
'{{#items}}Item: {{name}}\n{{/items}}',
{'items': [{'name': 'A'}, {'name': 'B'}]},
);
// Result: 'Item: A\nItem: B\n'BundleSkill(
id: 'analyzer',
name: 'Text Analyzer',
description: 'Analyzes text content',
inputSchema: {
'type': 'object',
'properties': {
'text': {'type': 'string'},
},
},
outputSchema: {
'type': 'object',
'properties': {
'sentiment': {'type': 'string'},
'topics': {'type': 'array'},
},
},
executor: 'llm',
prompt: 'Analyze: {{input.text}}',
tags: ['nlp', 'analysis'],
)BundleProfile(
id: 'expert',
name: 'Domain Expert',
description: 'Expert in specific domain',
systemPrompt: '''
You are an expert in {{domain}}.
Help the user with {{task}}.
''',
variables: ['domain', 'task'],
tags: ['expert'],
)BundleKnowledge(
id: 'faq',
name: 'FAQ Knowledge',
type: 'document',
content: 'Frequently asked questions...',
metadata: {
'source': 'internal',
'lastUpdated': '2025-01-01',
},
)| Method | Description |
|---|---|
load(path) |
Load bundle from file |
loadFromUrl(url) |
Load bundle from URL |
loadFromJson(json) |
Load from JSON data |
save(bundle, path) |
Save bundle to file |
| Method | Description |
|---|---|
validate(bundle) |
Validate entire bundle |
validateSkills(skills) |
Validate skills |
validateProfiles(profiles) |
Validate profiles |
validateKnowledge(knowledge) |
Validate knowledge |
| Method | Description |
|---|---|
evaluate(template, context) |
Evaluate expression |
validate(template) |
Validate expression syntax |
extractVariables(template) |
Extract variable names |
| Property/Method | Description |
|---|---|
identity |
Channel identity |
capabilities |
Channel capabilities |
events |
Stream of incoming events |
start() |
Start receiving events |
stop() |
Stop receiving events |
send(response) |
Send response to channel |
sendTyping(conversation) |
Send typing indicator |
edit(messageId, response) |
Edit sent message |
delete(messageId) |
Delete sent message |
react(messageId, reaction) |
Add reaction |
example/basic_bundle.dart- Basic bundle creationexample/bundle_loading.dart- Loading and saving bundlesexample/expression_language.dart- Expression evaluationexample/validation.dart- Bundle validationexample/channel_port.dart- Channel port usage
We welcome contributions! Please see our Contributing Guide for details.
This project is licensed under the MIT License - see the LICENSE file for details.