@matimo/core
v0.1.0-alpha.13
Published
Core SDK for Matimo: Framework-agnostic YAML-driven tool ecosystem for AI agents.
Downloads
637
Maintainers
Readme
@matimo/core — Core SDK for Matimo
Matimo core provides the TypeScript SDK that loads, validates, and executes YAML-defined tools across frameworks.
📦 Installation
Install the unified package (includes core exports):
# install unscope package which includes core and cli
npm install matimo
pnpm add matimo
# or install scoped core package directly
npm install @matimo/core
pnpm add @matimo/core🔧 Purpose
@matimo/core contains:
MatimoInstance— initialization, discovery, registry, and execution API- Executors — Command (shell), HTTP (REST with object/array embedding), Function (JS/TS)
- Policy Engine — content validation, risk classification, RBAC, integrity tracking
- Meta-Tools — 9 built-in tools for tool lifecycle management (create, validate, approve, reload, list, skill)
- Approval System — human-in-the-loop approval with interactive, auto-approve, and MCP patterns
- MCP Server — Model Context Protocol server with HTTP and stdio transports
- Decorator utilities (
@tool,setGlobalMatimoInstance) - Zod-based schema validation for YAML tool definitions
- Structured error handling —
MatimoErrorwith error chaining via optionalcausefield - OAuth2 authentication support (provider integrations in separate packages)
This package is intended to be imported by applications, CLIs, and provider packages.
🚀 Quick Start
import { MatimoInstance } from 'matimo';
// Auto-discover installed @matimo/* tool packages
const matimo = await MatimoInstance.init({ autoDiscover: true });
// List tools
console.log('Loaded', matimo.listTools().length, 'tools');
// Execute a tool
await matimo.execute('calculator', { operation: 'add', a: 1, b: 2 });🛠 Included Core Tools
@matimo/core includes 15 built-in tools:
Utility Tools
execute— Run shell commands with output capture, timeout, and working directory controlread— Read files with line range support and encoding detectionedit— Edit/replace content in files with backupsearch— Search files with grep patterns and contextweb— Fetch and parse web contentcalculator— Basic arithmetic operations
Meta-Tools (Tool Lifecycle Management)
matimo_validate_tool— Validate YAML against schema + policy rules, returns risk levelmatimo_create_tool— Write a new tool to disk with safety enforcement (forces draft + requires_approval)matimo_approve_tool— Promote a draft tool with HMAC-signed approval manifestmatimo_reload_tools— Hot-reload all tools into the live registry without restartmatimo_list_user_tools— List tools in a directory with risk classification and statusmatimo_create_skill— Create SKILL.md files with validated YAML frontmattermatimo_list_skills— List skills in a directory with name, description, and pathmatimo_get_skill— Read a skill's full content by name for agent contextmatimo_validate_skill— Validate a skill against the Agent Skills specification
All core tools use function-based execution (not shell commands) for better performance and reliability.
🧩 Usage Patterns
- Factory pattern:
MatimoInstance.init()+matimo.execute() - Decorator pattern: use
@tool()andsetGlobalMatimoInstance()for class-based code - LangChain integration: convert Matimo tools to LangChain function schemas
See the full SDK docs: docs/api-reference/SDK.md
⚙️ Executors
@matimo/core provides three execution engines:
FunctionExecutor (Recommended for Core Tools)
Executes TypeScript/JavaScript functions with type-safe parameters:
- ✅ Direct execution — No subprocess overhead
- ✅ Better performance — Direct async function calls
- ✅ Type safety — Proper TypeScript integration
- ✅ Error handling — Native exception handling
Core tools (execute, read, edit, search, web, calculator) all use function-based execution:
# Tool YAML:
execution:
type: function
code: './execute.ts' # Relative path to implementation
# File: execute.ts
export default async function execute(params: {
command: string
args?: string[]
cwd?: string
timeout?: number
}): Promise<{ success: boolean; stdout: string; stderr: string; exitCode: number }> {
// Implementation here
}HttpExecutor
Makes HTTP requests with automatic parameter embedding and response validation:
# Tool YAML:
execution:
type: http
method: POST
url: https://api.example.com/data
headers:
Authorization: 'Bearer {AUTH_TOKEN}'
body:
text: '{text}'
metadata: '{metadata}' # Objects/arrays automatically JSON-encodedKey features:
- ✅ Parameter embedding — Objects and arrays automatically JSON-encoded in request body
- ✅ Response validation — Validates output against
output_schemausing Zod - ✅ Error normalization — Converts Axios/HTTP errors to structured
MatimoError - ✅ Structured error details — Original error preserved via
error.causefield
CommandExecutor (Legacy Shell Execution)
Spawns shell processes for external commands:
// Tool YAML:
execution:
type: command
command: node
args: ["script.js", "{param1}"]
// Spawns: node script.js value1Use when:
- Executing external shell commands or legacy scripts
- Running tools from other packages that expect shell execution
- Most core Matimo tools now use function-based execution instead
🚨 Error Handling
All executors throw MatimoError (never generic Error) with structured context:
import { MatimoError, ErrorCode } from '@matimo/core';
try {
await matimo.execute('my-tool', params);
} catch (error) {
if (error instanceof MatimoError) {
console.error(`Error: ${error.message}`);
console.error(`Code: ${error.code}`);
console.error(`Details:`, error.details);
// Access original exception (if available)
if (error.cause) {
console.error(`Original error:`, error.cause);
}
}
}Error codes:
INVALID_SCHEMA— Tool definition or parameters invalidEXECUTION_FAILED— Tool execution failed (network, timeout, etc.)AUTH_FAILED— Authentication/authorization errorTOOL_NOT_FOUND— Tool not found in registry
Error chaining:
The optional cause field preserves the original error for debugging:
throw new MatimoError('HTTP request failed', ErrorCode.EXECUTION_FAILED, {
toolName: 'slack_send',
statusCode: 500,
details: { originalError: axiosError }
});
// Access via: error.cause or error.details.originalError🔐 Authentication & Security
Tools declare authentication requirements in YAML. @matimo/core supports:
- API keys (header/query injection)
- Bearer/basic tokens (automatic injection)
- OAuth2 (provider configurations via OAuth2Handler)
Credentials are loaded from environment variables by convention:
export SLACK_BOT_TOKEN=xoxb-...
export GMAIL_ACCESS_TOKEN=ya29-...
export NOTION_API_KEY=ntn_...Security notes:
- ✅ Secrets never logged (error messages exclude credential values)
- ✅ OAuth tokens refreshed automatically when expired
- ✅ HTTP Executor validates all authentication before making requests
- ✅ Missing credentials throw
MatimoError(AUTH_FAILED)with helpful guidance
🛡 Policy Engine
The policy engine provides defense-in-depth security for AI agent tool usage. Policy is defined at deploy time and Object.freeze()'d at runtime — agents cannot modify it.
import { MatimoInstance } from 'matimo';
import type { PolicyConfig } from 'matimo';
const policyConfig: PolicyConfig = {
allowedDomains: ['api.github.com', 'api.slack.com'],
allowedHttpMethods: ['GET', 'POST'],
allowCommandTools: false,
allowFunctionTools: false,
protectedNamespaces: ['matimo_'],
};
const matimo = await MatimoInstance.init({
toolPaths: ['./tools', './agent-tools'],
untrustedPaths: ['./agent-tools'],
policyConfig,
});Content Validator (9 Rules)
| Rule | Severity | What It Checks |
|------|----------|----------------|
| no-function-execution | critical | Blocks arbitrary code execution |
| no-command-execution | critical | Blocks shell injection |
| no-ssrf | critical | Blocks internal IPs/metadata endpoints |
| unauthorized-credential | high | Blocks unapproved credentials |
| reserved-namespace | high | Blocks hijacking of matimo_ prefix |
| forced-approval | medium | Enforces requires_approval: true |
| blocked-http-method | high | Blocks disallowed HTTP methods |
| blocked-domain | high | Blocks disallowed domains |
| forced-draft-status | medium | Enforces status: draft on new tools |
Risk Classification
| Risk Level | Criteria |
|-----------|----------|
| critical | execution.type: function |
| high | execution.type: command, HTTP DELETE, requires_approval: true |
| medium | HTTP POST, PUT, PATCH |
| low | HTTP GET, HEAD, OPTIONS |
See the full guide: docs/tool-development/POLICY_AND_LIFECYCLE.md
🔄 Tool Lifecycle (Create → Approve → Reload → Use)
Agents can create tools at runtime with full policy enforcement:
// 1. Create — writes YAML to disk (forces draft + requires_approval)
await matimo.execute('matimo_create_tool', {
name: 'city_lookup',
target_dir: './agent-tools',
yaml_content: `
name: city_lookup
version: '1.0.0'
description: Look up user information including city and address details
parameters:
id: { type: string, required: true }
execution:
type: http
method: GET
url: 'https://jsonplaceholder.typicode.com/users/{id}'
`,
});
// 2. Approve — re-validates, signs HMAC, updates status to approved
await matimo.execute('matimo_approve_tool', {
name: 'city_lookup',
tool_dir: './agent-tools',
});
// 3. Reload — clears registry, re-reads YAML, re-validates untrusted tools
await matimo.execute('matimo_reload_tools', {});
// 4. Use — tool is now in the live registry
const result = await matimo.execute('city_lookup', { id: '1' });This lifecycle works identically across SDK, LangChain, and MCP interfaces.
See the full reference: docs/tool-development/META_TOOLS.md
✅ Approval System
Tools with requires_approval: true require human confirmation before execution:
import { getGlobalApprovalHandler } from 'matimo';
// Interactive terminal approval
getGlobalApprovalHandler().setApprovalCallback(async (request) => {
console.log(`Tool: ${request.toolName}`);
console.log(`Params: ${JSON.stringify(request.params)}`);
// return true to approve, false to reject
return await promptUser('Approve? (y/n)');
});
// Auto-approve (CI/CD only)
process.env.MATIMO_AUTO_APPROVE = 'true';
// Pre-approved patterns
process.env.MATIMO_APPROVED_PATTERNS = 'calculator,weather_*';MCP approval: MCP clients pass _matimo_approved: true in arguments for tools that require approval.
🌐 MCP Server
Serve Matimo tools via the Model Context Protocol:
import { MCPServer } from 'matimo';
const server = new MCPServer({
transport: 'http',
port: 3000,
toolPaths: ['./tools'],
policyConfig: { allowCommandTools: false },
mcpToken: process.env.MCP_TOKEN,
});
await server.start();
// Tools available at POST http://localhost:3000/mcpSupports:
- HTTP and stdio transports
- Bearer token authentication
- Tool lifecycle via meta-tools (create, approve, reload)
- Automatic
notifications/tools/list_changedon reload
See: docs/MCP.md
✅ Validation & Output Schema
All tool execution includes automatic validation:
Input Validation:
- Tool YAML definitions validated against Zod schema on load
- Parameters validated against tool's declared
parametersschema - Invalid parameters throw
MatimoError(INVALID_SCHEMA)
Output Validation:
- HTTP executor validates response against tool's
output_schema - Function executor validates return value against
output_schema(for HTTP tools) - Invalid responses/returns throw
MatimoError(EXECUTION_FAILED) - Zod provides detailed validation error messages
Example (core execute tool):
# Definition: packages/core/tools/execute/definition.yaml
execution:
type: function
code: './execute.ts'
output_schema:
type: object
properties:
success: { type: boolean }
exitCode: { type: number }
stdout: { type: string }
stderr: { type: string }
required: [success, exitCode, stdout, stderr]Invalid parameters or responses trigger validation errors with structured details.
🧪 Testing & Development
To run core package tests:
pnpm --filter "@matimo/core" testTo build:
pnpm --filter "@matimo/core" build📚 Documentation
- Quick Start
- API Reference
- Policy & Lifecycle Guide
- Meta-Tools Reference
- Approval System
- MCP Server
- Tool Specification
- Adding Tools
- Contributing
Part of the Matimo ecosystem — define tools once, use them everywhere.
