From 262c677d8b8710d6f75025581daae3f0b1e3a3bd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 8 Feb 2026 09:35:58 +0000 Subject: [PATCH 1/4] Initial plan From a4baee25cd351339afccb396ee51367ac9105d0e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 8 Feb 2026 09:41:08 +0000 Subject: [PATCH 2/4] Add MCP (Model Context Protocol) schemas and tests Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- packages/spec/PROTOCOL_MAP.md | 1 + packages/spec/README.md | 132 ++- .../spec/json-schema/ai/MCPCapability.json | 42 + .../spec/json-schema/ai/MCPClientConfig.json | 906 ++++++++++++++++++ packages/spec/json-schema/ai/MCPPrompt.json | 99 ++ .../json-schema/ai/MCPPromptArgument.json | 36 + .../spec/json-schema/ai/MCPPromptMessage.json | 29 + .../spec/json-schema/ai/MCPPromptRequest.json | 24 + .../json-schema/ai/MCPPromptResponse.json | 46 + packages/spec/json-schema/ai/MCPResource.json | 95 ++ .../json-schema/ai/MCPResourceRequest.json | 24 + .../json-schema/ai/MCPResourceResponse.json | 107 +++ .../json-schema/ai/MCPResourceTemplate.json | 83 ++ .../spec/json-schema/ai/MCPResourceType.json | 15 + .../spec/json-schema/ai/MCPServerConfig.json | 851 ++++++++++++++++ .../spec/json-schema/ai/MCPServerInfo.json | 83 ++ packages/spec/json-schema/ai/MCPTool.json | 266 +++++ .../json-schema/ai/MCPToolCallRequest.json | 52 + .../json-schema/ai/MCPToolCallResponse.json | 57 ++ .../spec/json-schema/ai/MCPToolParameter.json | 75 ++ .../json-schema/ai/MCPTransportConfig.json | 105 ++ .../spec/json-schema/ai/MCPTransportType.json | 15 + .../spec/json-schema/api/ApiCapabilities.json | 20 + packages/spec/json-schema/api/ApiRoutes.json | 40 +- .../api/CompileManifestResponse.json | 30 + .../api/DisablePackageResponse.json | 30 + packages/spec/json-schema/api/Discovery.json | 60 +- .../json-schema/api/DispatcherConfig.json | 95 ++ .../spec/json-schema/api/DispatcherRoute.json | 67 ++ .../api/EnablePackageResponse.json | 30 + .../json-schema/api/GetDiscoveryResponse.json | 60 +- .../json-schema/api/GetPackageResponse.json | 30 + .../api/InstallPackageRequest.json | 30 + .../api/InstallPackageResponse.json | 30 + .../json-schema/api/ListPackagesResponse.json | 30 + .../json-schema/hub/ComposerResponse.json | 30 + .../kernel/DisablePackageResponse.json | 30 + .../kernel/EnablePackageResponse.json | 30 + .../kernel/GetPackageResponse.json | 30 + .../kernel/InstallPackageRequest.json | 30 + .../kernel/InstallPackageResponse.json | 30 + .../json-schema/kernel/InstalledPackage.json | 30 + .../kernel/ListPackagesResponse.json | 30 + .../spec/json-schema/kernel/Manifest.json | 30 + .../json-schema/system/CoreServiceName.json | 6 +- .../json-schema/system/KernelServiceMap.json | 6 +- .../json-schema/system/ServiceConfig.json | 6 +- .../json-schema/system/ServiceStatus.json | 6 +- packages/spec/src/ai/index.ts | 2 + packages/spec/src/ai/mcp.test.ts | 594 ++++++++++++ packages/spec/src/ai/mcp.zod.ts | 483 ++++++++++ 51 files changed, 5039 insertions(+), 29 deletions(-) create mode 100644 packages/spec/json-schema/ai/MCPCapability.json create mode 100644 packages/spec/json-schema/ai/MCPClientConfig.json create mode 100644 packages/spec/json-schema/ai/MCPPrompt.json create mode 100644 packages/spec/json-schema/ai/MCPPromptArgument.json create mode 100644 packages/spec/json-schema/ai/MCPPromptMessage.json create mode 100644 packages/spec/json-schema/ai/MCPPromptRequest.json create mode 100644 packages/spec/json-schema/ai/MCPPromptResponse.json create mode 100644 packages/spec/json-schema/ai/MCPResource.json create mode 100644 packages/spec/json-schema/ai/MCPResourceRequest.json create mode 100644 packages/spec/json-schema/ai/MCPResourceResponse.json create mode 100644 packages/spec/json-schema/ai/MCPResourceTemplate.json create mode 100644 packages/spec/json-schema/ai/MCPResourceType.json create mode 100644 packages/spec/json-schema/ai/MCPServerConfig.json create mode 100644 packages/spec/json-schema/ai/MCPServerInfo.json create mode 100644 packages/spec/json-schema/ai/MCPTool.json create mode 100644 packages/spec/json-schema/ai/MCPToolCallRequest.json create mode 100644 packages/spec/json-schema/ai/MCPToolCallResponse.json create mode 100644 packages/spec/json-schema/ai/MCPToolParameter.json create mode 100644 packages/spec/json-schema/ai/MCPTransportConfig.json create mode 100644 packages/spec/json-schema/ai/MCPTransportType.json create mode 100644 packages/spec/json-schema/api/DispatcherConfig.json create mode 100644 packages/spec/json-schema/api/DispatcherRoute.json create mode 100644 packages/spec/src/ai/mcp.test.ts create mode 100644 packages/spec/src/ai/mcp.zod.ts diff --git a/packages/spec/PROTOCOL_MAP.md b/packages/spec/PROTOCOL_MAP.md index 09d912324..71dab767c 100644 --- a/packages/spec/PROTOCOL_MAP.md +++ b/packages/spec/PROTOCOL_MAP.md @@ -75,6 +75,7 @@ This document serves as the **Grand Map** of the ObjectStack specification. It l | :--- | :--- | :--- | | [`agent.zod.ts`](src/ai/agent.zod.ts) | ⭐ | **AI Agent**. Attributes of an AI assistant (role, personality, model). | | [`agent-action.zod.ts`](src/ai/agent-action.zod.ts) | ⭐ | **Tools & Actions**. Capabilities exposed to the AI (Function Calling). | +| [`mcp.zod.ts`](src/ai/mcp.zod.ts) | ⭐ | **Model Context Protocol (MCP)**. Standard protocol for connecting AI to tools, resources, and data sources. | | [`rag-pipeline.zod.ts`](src/ai/rag-pipeline.zod.ts) | ⭐ | **RAG**. Retrieval Augmented Generation configurations. | | [`model-registry.zod.ts`](src/ai/model-registry.zod.ts) | | **LLM Registry**. Configuration for model providers (OpenAI, Anthropic). | | [`conversation.zod.ts`](src/ai/conversation.zod.ts) | | **Chat Session**. History and context management for AI chats. | diff --git a/packages/spec/README.md b/packages/spec/README.md index e591d3b1f..82108ceb9 100644 --- a/packages/spec/README.md +++ b/packages/spec/README.md @@ -8,7 +8,7 @@ The **Source of Truth** for the ObjectStack Protocol. Contains strictly typed Zo - **Data**: Objects, Fields, Validation Rules. - **UI**: Views, Layouts, Dashboards. - **Automation**: Flows, Workflows, Triggers. -- **AI**: Agents, RAG Pipelines, Models. +- **AI**: Agents, RAG Pipelines, Models, MCP Servers. ## Usage @@ -58,3 +58,133 @@ if (result.success) { console.log('Valid object:', result.data); } ``` + +## MCP (Model Context Protocol) Integration + +Define MCP servers to connect AI agents to your ObjectStack data and tools: + +```typescript +import { MCPServerConfigSchema } from '@objectstack/spec/ai'; + +// Define an MCP server exposing ObjectStack data +export const objectStackMCP = MCPServerConfigSchema.parse({ + name: 'objectstack_mcp', + label: 'ObjectStack MCP Server', + description: 'Connects AI agents to ObjectStack data and workflows', + + serverInfo: { + name: 'ObjectStack MCP', + version: '1.0.0', + capabilities: { + resources: true, + resourceTemplates: true, + tools: true, + prompts: true, + }, + }, + + transport: { + type: 'http', + url: 'https://api.objectstack.ai/mcp', + auth: { + type: 'bearer', + secretRef: 'system:mcp_api_key', + }, + }, + + // Expose data as resources + resourceTemplates: [ + { + uriPattern: 'objectstack://objects/{objectName}', + name: 'Object Data', + description: 'Access object records', + parameters: [ + { + name: 'objectName', + type: 'string', + required: true, + description: 'Name of the object to access', + }, + ], + handler: 'resources.getObjectData', + }, + ], + + // Expose workflows as tools + tools: [ + { + name: 'create_record', + description: 'Create a new record in any object', + parameters: [ + { + name: 'object', + type: 'string', + description: 'Object name (e.g., "account", "contact")', + required: true, + }, + { + name: 'data', + type: 'object', + description: 'Record data as key-value pairs', + required: true, + }, + ], + handler: 'flows.create_record', + sideEffects: 'write', + requiresConfirmation: true, + }, + { + name: 'search_records', + description: 'Search for records using natural language or filters', + parameters: [ + { + name: 'object', + type: 'string', + description: 'Object to search in', + required: true, + }, + { + name: 'query', + type: 'string', + description: 'Search query', + required: true, + }, + ], + handler: 'data.search', + sideEffects: 'read', + }, + ], + + // Provide prompt templates + prompts: [ + { + name: 'analyze_customer_data', + description: 'Analyze customer data and generate insights', + messages: [ + { + role: 'system', + content: 'You are a data analyst specializing in customer insights.', + }, + { + role: 'user', + content: 'Analyze the following customer data and provide insights: {{customer_data}}', + }, + ], + arguments: [ + { + name: 'customer_data', + type: 'string', + required: true, + description: 'Customer data in JSON format', + }, + ], + }, + ], + + autoStart: true, + healthCheck: { + enabled: true, + interval: 60000, + }, +}); +``` diff --git a/packages/spec/json-schema/ai/MCPCapability.json b/packages/spec/json-schema/ai/MCPCapability.json new file mode 100644 index 000000000..4078261ec --- /dev/null +++ b/packages/spec/json-schema/ai/MCPCapability.json @@ -0,0 +1,42 @@ +{ + "$ref": "#/definitions/MCPCapability", + "definitions": { + "MCPCapability": { + "type": "object", + "properties": { + "resources": { + "type": "boolean", + "default": false, + "description": "Supports resource listing and retrieval" + }, + "resourceTemplates": { + "type": "boolean", + "default": false, + "description": "Supports dynamic resource templates" + }, + "tools": { + "type": "boolean", + "default": false, + "description": "Supports tool/function calling" + }, + "prompts": { + "type": "boolean", + "default": false, + "description": "Supports prompt templates" + }, + "sampling": { + "type": "boolean", + "default": false, + "description": "Supports sampling from LLMs" + }, + "logging": { + "type": "boolean", + "default": false, + "description": "Supports logging and debugging" + } + }, + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/ai/MCPClientConfig.json b/packages/spec/json-schema/ai/MCPClientConfig.json new file mode 100644 index 000000000..8be682bc0 --- /dev/null +++ b/packages/spec/json-schema/ai/MCPClientConfig.json @@ -0,0 +1,906 @@ +{ + "$ref": "#/definitions/MCPClientConfig", + "definitions": { + "MCPClientConfig": { + "type": "object", + "properties": { + "servers": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "pattern": "^[a-z_][a-z0-9_]*$", + "description": "Server unique identifier (snake_case)" + }, + "label": { + "type": "string", + "description": "Display name" + }, + "description": { + "type": "string" + }, + "serverInfo": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Server name" + }, + "version": { + "type": "string", + "description": "Server version (semver)" + }, + "description": { + "type": "string" + }, + "capabilities": { + "type": "object", + "properties": { + "resources": { + "type": "boolean", + "default": false, + "description": "Supports resource listing and retrieval" + }, + "resourceTemplates": { + "type": "boolean", + "default": false, + "description": "Supports dynamic resource templates" + }, + "tools": { + "type": "boolean", + "default": false, + "description": "Supports tool/function calling" + }, + "prompts": { + "type": "boolean", + "default": false, + "description": "Supports prompt templates" + }, + "sampling": { + "type": "boolean", + "default": false, + "description": "Supports sampling from LLMs" + }, + "logging": { + "type": "boolean", + "default": false, + "description": "Supports logging and debugging" + } + }, + "additionalProperties": false + }, + "protocolVersion": { + "type": "string", + "default": "2024-11-05", + "description": "MCP protocol version" + }, + "vendor": { + "type": "string", + "description": "Server vendor/provider" + }, + "homepage": { + "type": "string", + "format": "uri", + "description": "Server homepage URL" + }, + "documentation": { + "type": "string", + "format": "uri", + "description": "Documentation URL" + } + }, + "required": [ + "name", + "version", + "capabilities" + ], + "additionalProperties": false + }, + "transport": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "stdio", + "http", + "websocket", + "grpc" + ] + }, + "url": { + "type": "string", + "format": "uri", + "description": "Server URL (for HTTP/WebSocket/gRPC)" + }, + "headers": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom headers for requests" + }, + "auth": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "none", + "bearer", + "api_key", + "oauth2", + "custom" + ], + "default": "none" + }, + "token": { + "type": "string", + "description": "Bearer token or API key" + }, + "secretRef": { + "type": "string", + "description": "Reference to stored secret" + }, + "headerName": { + "type": "string", + "description": "Custom auth header name" + } + }, + "additionalProperties": false + }, + "timeout": { + "type": "integer", + "exclusiveMinimum": 0, + "default": 30000, + "description": "Request timeout in milliseconds" + }, + "retryAttempts": { + "type": "integer", + "minimum": 0, + "maximum": 5, + "default": 3 + }, + "retryDelay": { + "type": "integer", + "exclusiveMinimum": 0, + "default": 1000, + "description": "Delay between retries in milliseconds" + }, + "command": { + "type": "string", + "description": "Command to execute (for stdio transport)" + }, + "args": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Command arguments" + }, + "env": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Environment variables" + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the process" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + "resources": { + "type": "array", + "items": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "description": "Unique resource identifier (e.g., \"objectstack://objects/account/ABC123\")" + }, + "name": { + "type": "string", + "description": "Human-readable resource name" + }, + "description": { + "type": "string", + "description": "Resource description for AI consumption" + }, + "mimeType": { + "type": "string", + "description": "MIME type (e.g., \"application/json\", \"text/plain\")" + }, + "resourceType": { + "type": "string", + "enum": [ + "text", + "json", + "binary", + "stream" + ], + "default": "json" + }, + "content": { + "description": "Resource content (for static resources)" + }, + "contentUrl": { + "type": "string", + "format": "uri", + "description": "URL to fetch content dynamically" + }, + "size": { + "type": "integer", + "minimum": 0, + "description": "Resource size in bytes" + }, + "lastModified": { + "type": "string", + "format": "date-time", + "description": "Last modification timestamp (ISO 8601)" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for resource categorization" + }, + "permissions": { + "type": "object", + "properties": { + "read": { + "type": "boolean", + "default": true + }, + "write": { + "type": "boolean", + "default": false + }, + "delete": { + "type": "boolean", + "default": false + } + }, + "additionalProperties": false + }, + "cacheable": { + "type": "boolean", + "default": true, + "description": "Whether this resource can be cached" + }, + "cacheMaxAge": { + "type": "integer", + "minimum": 0, + "description": "Cache max age in seconds" + } + }, + "required": [ + "uri", + "name" + ], + "additionalProperties": false + }, + "description": "Static resources" + }, + "resourceTemplates": { + "type": "array", + "items": { + "type": "object", + "properties": { + "uriPattern": { + "type": "string", + "description": "URI pattern with variables (e.g., \"objectstack://objects/{objectName}/{recordId}\")" + }, + "name": { + "type": "string", + "description": "Template name" + }, + "description": { + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Parameter name" + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean" + ], + "default": "string" + }, + "required": { + "type": "boolean", + "default": true + }, + "description": { + "type": "string" + }, + "pattern": { + "type": "string", + "description": "Regex validation pattern" + }, + "default": {} + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "description": "URI parameters" + }, + "handler": { + "type": "string", + "description": "Handler function name for dynamic generation" + }, + "mimeType": { + "type": "string" + }, + "resourceType": { + "type": "string", + "enum": [ + "text", + "json", + "binary", + "stream" + ], + "default": "json" + } + }, + "required": [ + "uriPattern", + "name", + "parameters" + ], + "additionalProperties": false + }, + "description": "Dynamic resource templates" + }, + "tools": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "pattern": "^[a-z_][a-z0-9_]*$", + "description": "Tool function name (snake_case)" + }, + "description": { + "type": "string", + "description": "Tool description for AI consumption (be detailed and specific)" + }, + "parameters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Parameter name" + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array" + ] + }, + "description": { + "type": "string", + "description": "Parameter description for AI consumption" + }, + "required": { + "type": "boolean", + "default": false + }, + "default": {}, + "enum": { + "type": "array", + "items": {}, + "description": "Allowed values" + }, + "pattern": { + "type": "string", + "description": "Regex validation pattern (for strings)" + }, + "minimum": { + "type": "number", + "description": "Minimum value (for numbers)" + }, + "maximum": { + "type": "number", + "description": "Maximum value (for numbers)" + }, + "minLength": { + "type": "integer", + "minimum": 0, + "description": "Minimum length (for strings/arrays)" + }, + "maxLength": { + "type": "integer", + "minimum": 0, + "description": "Maximum length (for strings/arrays)" + }, + "properties": { + "type": "object", + "additionalProperties": {}, + "description": "Properties for object types" + }, + "items": { + "description": "Item schema for array types" + } + }, + "required": [ + "name", + "type", + "description" + ], + "additionalProperties": false + }, + "description": "Tool parameters" + }, + "returns": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array", + "void" + ] + }, + "description": { + "type": "string" + }, + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Parameter name" + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array" + ] + }, + "description": { + "type": "string", + "description": "Parameter description for AI consumption" + }, + "required": { + "type": "boolean", + "default": false + }, + "default": {}, + "enum": { + "type": "array", + "items": {}, + "description": "Allowed values" + }, + "pattern": { + "type": "string", + "description": "Regex validation pattern (for strings)" + }, + "minimum": { + "type": "number", + "description": "Minimum value (for numbers)" + }, + "maximum": { + "type": "number", + "description": "Maximum value (for numbers)" + }, + "minLength": { + "type": "integer", + "minimum": 0, + "description": "Minimum length (for strings/arrays)" + }, + "maxLength": { + "type": "integer", + "minimum": 0, + "description": "Maximum length (for strings/arrays)" + }, + "properties": { + "type": "object", + "additionalProperties": {}, + "description": "Properties for object types" + }, + "items": { + "description": "Item schema for array types" + } + }, + "required": [ + "name", + "type", + "description" + ], + "additionalProperties": false, + "description": "Return value schema" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + "handler": { + "type": "string", + "description": "Handler function or endpoint reference" + }, + "async": { + "type": "boolean", + "default": true, + "description": "Whether the tool executes asynchronously" + }, + "timeout": { + "type": "integer", + "exclusiveMinimum": 0, + "description": "Execution timeout in milliseconds" + }, + "sideEffects": { + "type": "string", + "enum": [ + "none", + "read", + "write", + "delete" + ], + "default": "read", + "description": "Tool side effects" + }, + "requiresConfirmation": { + "type": "boolean", + "default": false, + "description": "Require user confirmation before execution" + }, + "confirmationMessage": { + "type": "string" + }, + "examples": { + "type": "array", + "items": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "parameters": { + "type": "object", + "additionalProperties": {} + }, + "result": {} + }, + "required": [ + "description", + "parameters" + ], + "additionalProperties": false + }, + "description": "Usage examples for AI learning" + }, + "category": { + "type": "string", + "description": "Tool category (e.g., \"data\", \"workflow\", \"analytics\")" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "deprecated": { + "type": "boolean", + "default": false + }, + "version": { + "type": "string", + "default": "1.0.0" + } + }, + "required": [ + "name", + "description", + "parameters", + "handler" + ], + "additionalProperties": false + }, + "description": "Available tools" + }, + "prompts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "pattern": "^[a-z_][a-z0-9_]*$", + "description": "Prompt template name (snake_case)" + }, + "description": { + "type": "string", + "description": "Prompt description" + }, + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "role": { + "type": "string", + "enum": [ + "system", + "user", + "assistant" + ], + "description": "Message role" + }, + "content": { + "type": "string", + "description": "Message content (can include {{variable}} placeholders)" + } + }, + "required": [ + "role", + "content" + ], + "additionalProperties": false + }, + "description": "Prompt message sequence" + }, + "arguments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Argument name" + }, + "description": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean" + ], + "default": "string" + }, + "required": { + "type": "boolean", + "default": false + }, + "default": {} + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "description": "Dynamic arguments for the prompt" + }, + "category": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "version": { + "type": "string", + "default": "1.0.0" + } + }, + "required": [ + "name", + "messages" + ], + "additionalProperties": false + }, + "description": "Prompt templates" + }, + "autoStart": { + "type": "boolean", + "default": false, + "description": "Auto-start server on system boot" + }, + "restartOnFailure": { + "type": "boolean", + "default": true, + "description": "Auto-restart on failure" + }, + "healthCheck": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "default": true + }, + "interval": { + "type": "integer", + "exclusiveMinimum": 0, + "default": 60000, + "description": "Health check interval in milliseconds" + }, + "timeout": { + "type": "integer", + "exclusiveMinimum": 0, + "default": 5000, + "description": "Health check timeout in milliseconds" + }, + "endpoint": { + "type": "string", + "description": "Health check endpoint (for HTTP servers)" + } + }, + "additionalProperties": false + }, + "permissions": { + "type": "object", + "properties": { + "allowedAgents": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Agent names allowed to use this server" + }, + "allowedUsers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "User IDs allowed to use this server" + }, + "requireAuth": { + "type": "boolean", + "default": true + } + }, + "additionalProperties": false + }, + "rateLimit": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "default": false + }, + "requestsPerMinute": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "requestsPerHour": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "burstSize": { + "type": "integer", + "exclusiveMinimum": 0 + } + }, + "additionalProperties": false + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "status": { + "type": "string", + "enum": [ + "active", + "inactive", + "maintenance", + "deprecated" + ], + "default": "active" + }, + "version": { + "type": "string", + "default": "1.0.0" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "name", + "label", + "serverInfo", + "transport" + ], + "additionalProperties": false + }, + "description": "MCP servers to connect to" + }, + "defaultTimeout": { + "type": "integer", + "exclusiveMinimum": 0, + "default": 30000, + "description": "Default timeout for requests" + }, + "enableCaching": { + "type": "boolean", + "default": true, + "description": "Enable client-side caching" + }, + "cacheMaxAge": { + "type": "integer", + "minimum": 0, + "default": 300, + "description": "Cache max age in seconds" + }, + "retryAttempts": { + "type": "integer", + "minimum": 0, + "maximum": 5, + "default": 3 + }, + "retryDelay": { + "type": "integer", + "exclusiveMinimum": 0, + "default": 1000 + }, + "enableLogging": { + "type": "boolean", + "default": true + }, + "logLevel": { + "type": "string", + "enum": [ + "debug", + "info", + "warn", + "error" + ], + "default": "info" + } + }, + "required": [ + "servers" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/ai/MCPPrompt.json b/packages/spec/json-schema/ai/MCPPrompt.json new file mode 100644 index 000000000..ef1af53fb --- /dev/null +++ b/packages/spec/json-schema/ai/MCPPrompt.json @@ -0,0 +1,99 @@ +{ + "$ref": "#/definitions/MCPPrompt", + "definitions": { + "MCPPrompt": { + "type": "object", + "properties": { + "name": { + "type": "string", + "pattern": "^[a-z_][a-z0-9_]*$", + "description": "Prompt template name (snake_case)" + }, + "description": { + "type": "string", + "description": "Prompt description" + }, + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "role": { + "type": "string", + "enum": [ + "system", + "user", + "assistant" + ], + "description": "Message role" + }, + "content": { + "type": "string", + "description": "Message content (can include {{variable}} placeholders)" + } + }, + "required": [ + "role", + "content" + ], + "additionalProperties": false + }, + "description": "Prompt message sequence" + }, + "arguments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Argument name" + }, + "description": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean" + ], + "default": "string" + }, + "required": { + "type": "boolean", + "default": false + }, + "default": {} + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "description": "Dynamic arguments for the prompt" + }, + "category": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "version": { + "type": "string", + "default": "1.0.0" + } + }, + "required": [ + "name", + "messages" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/ai/MCPPromptArgument.json b/packages/spec/json-schema/ai/MCPPromptArgument.json new file mode 100644 index 000000000..36290a870 --- /dev/null +++ b/packages/spec/json-schema/ai/MCPPromptArgument.json @@ -0,0 +1,36 @@ +{ + "$ref": "#/definitions/MCPPromptArgument", + "definitions": { + "MCPPromptArgument": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Argument name" + }, + "description": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean" + ], + "default": "string" + }, + "required": { + "type": "boolean", + "default": false + }, + "default": {} + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/ai/MCPPromptMessage.json b/packages/spec/json-schema/ai/MCPPromptMessage.json new file mode 100644 index 000000000..9d40eacdf --- /dev/null +++ b/packages/spec/json-schema/ai/MCPPromptMessage.json @@ -0,0 +1,29 @@ +{ + "$ref": "#/definitions/MCPPromptMessage", + "definitions": { + "MCPPromptMessage": { + "type": "object", + "properties": { + "role": { + "type": "string", + "enum": [ + "system", + "user", + "assistant" + ], + "description": "Message role" + }, + "content": { + "type": "string", + "description": "Message content (can include {{variable}} placeholders)" + } + }, + "required": [ + "role", + "content" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/ai/MCPPromptRequest.json b/packages/spec/json-schema/ai/MCPPromptRequest.json new file mode 100644 index 000000000..5701f9459 --- /dev/null +++ b/packages/spec/json-schema/ai/MCPPromptRequest.json @@ -0,0 +1,24 @@ +{ + "$ref": "#/definitions/MCPPromptRequest", + "definitions": { + "MCPPromptRequest": { + "type": "object", + "properties": { + "promptName": { + "type": "string", + "description": "Prompt template to use" + }, + "arguments": { + "type": "object", + "additionalProperties": {}, + "description": "Prompt arguments" + } + }, + "required": [ + "promptName" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/ai/MCPPromptResponse.json b/packages/spec/json-schema/ai/MCPPromptResponse.json new file mode 100644 index 000000000..5263f49c4 --- /dev/null +++ b/packages/spec/json-schema/ai/MCPPromptResponse.json @@ -0,0 +1,46 @@ +{ + "$ref": "#/definitions/MCPPromptResponse", + "definitions": { + "MCPPromptResponse": { + "type": "object", + "properties": { + "promptName": { + "type": "string" + }, + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "role": { + "type": "string", + "enum": [ + "system", + "user", + "assistant" + ], + "description": "Message role" + }, + "content": { + "type": "string", + "description": "Message content (can include {{variable}} placeholders)" + } + }, + "required": [ + "role", + "content" + ], + "additionalProperties": false + }, + "description": "Rendered prompt messages" + } + }, + "required": [ + "promptName", + "messages" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/ai/MCPResource.json b/packages/spec/json-schema/ai/MCPResource.json new file mode 100644 index 000000000..9e8a3b095 --- /dev/null +++ b/packages/spec/json-schema/ai/MCPResource.json @@ -0,0 +1,95 @@ +{ + "$ref": "#/definitions/MCPResource", + "definitions": { + "MCPResource": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "description": "Unique resource identifier (e.g., \"objectstack://objects/account/ABC123\")" + }, + "name": { + "type": "string", + "description": "Human-readable resource name" + }, + "description": { + "type": "string", + "description": "Resource description for AI consumption" + }, + "mimeType": { + "type": "string", + "description": "MIME type (e.g., \"application/json\", \"text/plain\")" + }, + "resourceType": { + "type": "string", + "enum": [ + "text", + "json", + "binary", + "stream" + ], + "default": "json" + }, + "content": { + "description": "Resource content (for static resources)" + }, + "contentUrl": { + "type": "string", + "format": "uri", + "description": "URL to fetch content dynamically" + }, + "size": { + "type": "integer", + "minimum": 0, + "description": "Resource size in bytes" + }, + "lastModified": { + "type": "string", + "format": "date-time", + "description": "Last modification timestamp (ISO 8601)" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for resource categorization" + }, + "permissions": { + "type": "object", + "properties": { + "read": { + "type": "boolean", + "default": true + }, + "write": { + "type": "boolean", + "default": false + }, + "delete": { + "type": "boolean", + "default": false + } + }, + "additionalProperties": false + }, + "cacheable": { + "type": "boolean", + "default": true, + "description": "Whether this resource can be cached" + }, + "cacheMaxAge": { + "type": "integer", + "minimum": 0, + "description": "Cache max age in seconds" + } + }, + "required": [ + "uri", + "name" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/ai/MCPResourceRequest.json b/packages/spec/json-schema/ai/MCPResourceRequest.json new file mode 100644 index 000000000..56ab9b84f --- /dev/null +++ b/packages/spec/json-schema/ai/MCPResourceRequest.json @@ -0,0 +1,24 @@ +{ + "$ref": "#/definitions/MCPResourceRequest", + "definitions": { + "MCPResourceRequest": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "description": "Resource URI to fetch" + }, + "parameters": { + "type": "object", + "additionalProperties": {}, + "description": "URI template parameters" + } + }, + "required": [ + "uri" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/ai/MCPResourceResponse.json b/packages/spec/json-schema/ai/MCPResourceResponse.json new file mode 100644 index 000000000..ee8131ea7 --- /dev/null +++ b/packages/spec/json-schema/ai/MCPResourceResponse.json @@ -0,0 +1,107 @@ +{ + "$ref": "#/definitions/MCPResourceResponse", + "definitions": { + "MCPResourceResponse": { + "type": "object", + "properties": { + "resource": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "description": "Unique resource identifier (e.g., \"objectstack://objects/account/ABC123\")" + }, + "name": { + "type": "string", + "description": "Human-readable resource name" + }, + "description": { + "type": "string", + "description": "Resource description for AI consumption" + }, + "mimeType": { + "type": "string", + "description": "MIME type (e.g., \"application/json\", \"text/plain\")" + }, + "resourceType": { + "type": "string", + "enum": [ + "text", + "json", + "binary", + "stream" + ], + "default": "json" + }, + "content": { + "description": "Resource content (for static resources)" + }, + "contentUrl": { + "type": "string", + "format": "uri", + "description": "URL to fetch content dynamically" + }, + "size": { + "type": "integer", + "minimum": 0, + "description": "Resource size in bytes" + }, + "lastModified": { + "type": "string", + "format": "date-time", + "description": "Last modification timestamp (ISO 8601)" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for resource categorization" + }, + "permissions": { + "type": "object", + "properties": { + "read": { + "type": "boolean", + "default": true + }, + "write": { + "type": "boolean", + "default": false + }, + "delete": { + "type": "boolean", + "default": false + } + }, + "additionalProperties": false + }, + "cacheable": { + "type": "boolean", + "default": true, + "description": "Whether this resource can be cached" + }, + "cacheMaxAge": { + "type": "integer", + "minimum": 0, + "description": "Cache max age in seconds" + } + }, + "required": [ + "uri", + "name" + ], + "additionalProperties": false + }, + "content": { + "description": "Resource content" + } + }, + "required": [ + "resource" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/ai/MCPResourceTemplate.json b/packages/spec/json-schema/ai/MCPResourceTemplate.json new file mode 100644 index 000000000..4715fadc4 --- /dev/null +++ b/packages/spec/json-schema/ai/MCPResourceTemplate.json @@ -0,0 +1,83 @@ +{ + "$ref": "#/definitions/MCPResourceTemplate", + "definitions": { + "MCPResourceTemplate": { + "type": "object", + "properties": { + "uriPattern": { + "type": "string", + "description": "URI pattern with variables (e.g., \"objectstack://objects/{objectName}/{recordId}\")" + }, + "name": { + "type": "string", + "description": "Template name" + }, + "description": { + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Parameter name" + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean" + ], + "default": "string" + }, + "required": { + "type": "boolean", + "default": true + }, + "description": { + "type": "string" + }, + "pattern": { + "type": "string", + "description": "Regex validation pattern" + }, + "default": {} + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "description": "URI parameters" + }, + "handler": { + "type": "string", + "description": "Handler function name for dynamic generation" + }, + "mimeType": { + "type": "string" + }, + "resourceType": { + "type": "string", + "enum": [ + "text", + "json", + "binary", + "stream" + ], + "default": "json" + } + }, + "required": [ + "uriPattern", + "name", + "parameters" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/ai/MCPResourceType.json b/packages/spec/json-schema/ai/MCPResourceType.json new file mode 100644 index 000000000..812311b3e --- /dev/null +++ b/packages/spec/json-schema/ai/MCPResourceType.json @@ -0,0 +1,15 @@ +{ + "$ref": "#/definitions/MCPResourceType", + "definitions": { + "MCPResourceType": { + "type": "string", + "enum": [ + "text", + "json", + "binary", + "stream" + ] + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/ai/MCPServerConfig.json b/packages/spec/json-schema/ai/MCPServerConfig.json new file mode 100644 index 000000000..6552cb495 --- /dev/null +++ b/packages/spec/json-schema/ai/MCPServerConfig.json @@ -0,0 +1,851 @@ +{ + "$ref": "#/definitions/MCPServerConfig", + "definitions": { + "MCPServerConfig": { + "type": "object", + "properties": { + "name": { + "type": "string", + "pattern": "^[a-z_][a-z0-9_]*$", + "description": "Server unique identifier (snake_case)" + }, + "label": { + "type": "string", + "description": "Display name" + }, + "description": { + "type": "string" + }, + "serverInfo": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Server name" + }, + "version": { + "type": "string", + "description": "Server version (semver)" + }, + "description": { + "type": "string" + }, + "capabilities": { + "type": "object", + "properties": { + "resources": { + "type": "boolean", + "default": false, + "description": "Supports resource listing and retrieval" + }, + "resourceTemplates": { + "type": "boolean", + "default": false, + "description": "Supports dynamic resource templates" + }, + "tools": { + "type": "boolean", + "default": false, + "description": "Supports tool/function calling" + }, + "prompts": { + "type": "boolean", + "default": false, + "description": "Supports prompt templates" + }, + "sampling": { + "type": "boolean", + "default": false, + "description": "Supports sampling from LLMs" + }, + "logging": { + "type": "boolean", + "default": false, + "description": "Supports logging and debugging" + } + }, + "additionalProperties": false + }, + "protocolVersion": { + "type": "string", + "default": "2024-11-05", + "description": "MCP protocol version" + }, + "vendor": { + "type": "string", + "description": "Server vendor/provider" + }, + "homepage": { + "type": "string", + "format": "uri", + "description": "Server homepage URL" + }, + "documentation": { + "type": "string", + "format": "uri", + "description": "Documentation URL" + } + }, + "required": [ + "name", + "version", + "capabilities" + ], + "additionalProperties": false + }, + "transport": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "stdio", + "http", + "websocket", + "grpc" + ] + }, + "url": { + "type": "string", + "format": "uri", + "description": "Server URL (for HTTP/WebSocket/gRPC)" + }, + "headers": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom headers for requests" + }, + "auth": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "none", + "bearer", + "api_key", + "oauth2", + "custom" + ], + "default": "none" + }, + "token": { + "type": "string", + "description": "Bearer token or API key" + }, + "secretRef": { + "type": "string", + "description": "Reference to stored secret" + }, + "headerName": { + "type": "string", + "description": "Custom auth header name" + } + }, + "additionalProperties": false + }, + "timeout": { + "type": "integer", + "exclusiveMinimum": 0, + "default": 30000, + "description": "Request timeout in milliseconds" + }, + "retryAttempts": { + "type": "integer", + "minimum": 0, + "maximum": 5, + "default": 3 + }, + "retryDelay": { + "type": "integer", + "exclusiveMinimum": 0, + "default": 1000, + "description": "Delay between retries in milliseconds" + }, + "command": { + "type": "string", + "description": "Command to execute (for stdio transport)" + }, + "args": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Command arguments" + }, + "env": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Environment variables" + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the process" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + "resources": { + "type": "array", + "items": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "description": "Unique resource identifier (e.g., \"objectstack://objects/account/ABC123\")" + }, + "name": { + "type": "string", + "description": "Human-readable resource name" + }, + "description": { + "type": "string", + "description": "Resource description for AI consumption" + }, + "mimeType": { + "type": "string", + "description": "MIME type (e.g., \"application/json\", \"text/plain\")" + }, + "resourceType": { + "type": "string", + "enum": [ + "text", + "json", + "binary", + "stream" + ], + "default": "json" + }, + "content": { + "description": "Resource content (for static resources)" + }, + "contentUrl": { + "type": "string", + "format": "uri", + "description": "URL to fetch content dynamically" + }, + "size": { + "type": "integer", + "minimum": 0, + "description": "Resource size in bytes" + }, + "lastModified": { + "type": "string", + "format": "date-time", + "description": "Last modification timestamp (ISO 8601)" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for resource categorization" + }, + "permissions": { + "type": "object", + "properties": { + "read": { + "type": "boolean", + "default": true + }, + "write": { + "type": "boolean", + "default": false + }, + "delete": { + "type": "boolean", + "default": false + } + }, + "additionalProperties": false + }, + "cacheable": { + "type": "boolean", + "default": true, + "description": "Whether this resource can be cached" + }, + "cacheMaxAge": { + "type": "integer", + "minimum": 0, + "description": "Cache max age in seconds" + } + }, + "required": [ + "uri", + "name" + ], + "additionalProperties": false + }, + "description": "Static resources" + }, + "resourceTemplates": { + "type": "array", + "items": { + "type": "object", + "properties": { + "uriPattern": { + "type": "string", + "description": "URI pattern with variables (e.g., \"objectstack://objects/{objectName}/{recordId}\")" + }, + "name": { + "type": "string", + "description": "Template name" + }, + "description": { + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Parameter name" + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean" + ], + "default": "string" + }, + "required": { + "type": "boolean", + "default": true + }, + "description": { + "type": "string" + }, + "pattern": { + "type": "string", + "description": "Regex validation pattern" + }, + "default": {} + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "description": "URI parameters" + }, + "handler": { + "type": "string", + "description": "Handler function name for dynamic generation" + }, + "mimeType": { + "type": "string" + }, + "resourceType": { + "type": "string", + "enum": [ + "text", + "json", + "binary", + "stream" + ], + "default": "json" + } + }, + "required": [ + "uriPattern", + "name", + "parameters" + ], + "additionalProperties": false + }, + "description": "Dynamic resource templates" + }, + "tools": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "pattern": "^[a-z_][a-z0-9_]*$", + "description": "Tool function name (snake_case)" + }, + "description": { + "type": "string", + "description": "Tool description for AI consumption (be detailed and specific)" + }, + "parameters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Parameter name" + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array" + ] + }, + "description": { + "type": "string", + "description": "Parameter description for AI consumption" + }, + "required": { + "type": "boolean", + "default": false + }, + "default": {}, + "enum": { + "type": "array", + "items": {}, + "description": "Allowed values" + }, + "pattern": { + "type": "string", + "description": "Regex validation pattern (for strings)" + }, + "minimum": { + "type": "number", + "description": "Minimum value (for numbers)" + }, + "maximum": { + "type": "number", + "description": "Maximum value (for numbers)" + }, + "minLength": { + "type": "integer", + "minimum": 0, + "description": "Minimum length (for strings/arrays)" + }, + "maxLength": { + "type": "integer", + "minimum": 0, + "description": "Maximum length (for strings/arrays)" + }, + "properties": { + "type": "object", + "additionalProperties": {}, + "description": "Properties for object types" + }, + "items": { + "description": "Item schema for array types" + } + }, + "required": [ + "name", + "type", + "description" + ], + "additionalProperties": false + }, + "description": "Tool parameters" + }, + "returns": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array", + "void" + ] + }, + "description": { + "type": "string" + }, + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Parameter name" + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array" + ] + }, + "description": { + "type": "string", + "description": "Parameter description for AI consumption" + }, + "required": { + "type": "boolean", + "default": false + }, + "default": {}, + "enum": { + "type": "array", + "items": {}, + "description": "Allowed values" + }, + "pattern": { + "type": "string", + "description": "Regex validation pattern (for strings)" + }, + "minimum": { + "type": "number", + "description": "Minimum value (for numbers)" + }, + "maximum": { + "type": "number", + "description": "Maximum value (for numbers)" + }, + "minLength": { + "type": "integer", + "minimum": 0, + "description": "Minimum length (for strings/arrays)" + }, + "maxLength": { + "type": "integer", + "minimum": 0, + "description": "Maximum length (for strings/arrays)" + }, + "properties": { + "type": "object", + "additionalProperties": {}, + "description": "Properties for object types" + }, + "items": { + "description": "Item schema for array types" + } + }, + "required": [ + "name", + "type", + "description" + ], + "additionalProperties": false, + "description": "Return value schema" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + "handler": { + "type": "string", + "description": "Handler function or endpoint reference" + }, + "async": { + "type": "boolean", + "default": true, + "description": "Whether the tool executes asynchronously" + }, + "timeout": { + "type": "integer", + "exclusiveMinimum": 0, + "description": "Execution timeout in milliseconds" + }, + "sideEffects": { + "type": "string", + "enum": [ + "none", + "read", + "write", + "delete" + ], + "default": "read", + "description": "Tool side effects" + }, + "requiresConfirmation": { + "type": "boolean", + "default": false, + "description": "Require user confirmation before execution" + }, + "confirmationMessage": { + "type": "string" + }, + "examples": { + "type": "array", + "items": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "parameters": { + "type": "object", + "additionalProperties": {} + }, + "result": {} + }, + "required": [ + "description", + "parameters" + ], + "additionalProperties": false + }, + "description": "Usage examples for AI learning" + }, + "category": { + "type": "string", + "description": "Tool category (e.g., \"data\", \"workflow\", \"analytics\")" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "deprecated": { + "type": "boolean", + "default": false + }, + "version": { + "type": "string", + "default": "1.0.0" + } + }, + "required": [ + "name", + "description", + "parameters", + "handler" + ], + "additionalProperties": false + }, + "description": "Available tools" + }, + "prompts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "pattern": "^[a-z_][a-z0-9_]*$", + "description": "Prompt template name (snake_case)" + }, + "description": { + "type": "string", + "description": "Prompt description" + }, + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "role": { + "type": "string", + "enum": [ + "system", + "user", + "assistant" + ], + "description": "Message role" + }, + "content": { + "type": "string", + "description": "Message content (can include {{variable}} placeholders)" + } + }, + "required": [ + "role", + "content" + ], + "additionalProperties": false + }, + "description": "Prompt message sequence" + }, + "arguments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Argument name" + }, + "description": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean" + ], + "default": "string" + }, + "required": { + "type": "boolean", + "default": false + }, + "default": {} + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "description": "Dynamic arguments for the prompt" + }, + "category": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "version": { + "type": "string", + "default": "1.0.0" + } + }, + "required": [ + "name", + "messages" + ], + "additionalProperties": false + }, + "description": "Prompt templates" + }, + "autoStart": { + "type": "boolean", + "default": false, + "description": "Auto-start server on system boot" + }, + "restartOnFailure": { + "type": "boolean", + "default": true, + "description": "Auto-restart on failure" + }, + "healthCheck": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "default": true + }, + "interval": { + "type": "integer", + "exclusiveMinimum": 0, + "default": 60000, + "description": "Health check interval in milliseconds" + }, + "timeout": { + "type": "integer", + "exclusiveMinimum": 0, + "default": 5000, + "description": "Health check timeout in milliseconds" + }, + "endpoint": { + "type": "string", + "description": "Health check endpoint (for HTTP servers)" + } + }, + "additionalProperties": false + }, + "permissions": { + "type": "object", + "properties": { + "allowedAgents": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Agent names allowed to use this server" + }, + "allowedUsers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "User IDs allowed to use this server" + }, + "requireAuth": { + "type": "boolean", + "default": true + } + }, + "additionalProperties": false + }, + "rateLimit": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "default": false + }, + "requestsPerMinute": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "requestsPerHour": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "burstSize": { + "type": "integer", + "exclusiveMinimum": 0 + } + }, + "additionalProperties": false + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "status": { + "type": "string", + "enum": [ + "active", + "inactive", + "maintenance", + "deprecated" + ], + "default": "active" + }, + "version": { + "type": "string", + "default": "1.0.0" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "name", + "label", + "serverInfo", + "transport" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/ai/MCPServerInfo.json b/packages/spec/json-schema/ai/MCPServerInfo.json new file mode 100644 index 000000000..480211b50 --- /dev/null +++ b/packages/spec/json-schema/ai/MCPServerInfo.json @@ -0,0 +1,83 @@ +{ + "$ref": "#/definitions/MCPServerInfo", + "definitions": { + "MCPServerInfo": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Server name" + }, + "version": { + "type": "string", + "description": "Server version (semver)" + }, + "description": { + "type": "string" + }, + "capabilities": { + "type": "object", + "properties": { + "resources": { + "type": "boolean", + "default": false, + "description": "Supports resource listing and retrieval" + }, + "resourceTemplates": { + "type": "boolean", + "default": false, + "description": "Supports dynamic resource templates" + }, + "tools": { + "type": "boolean", + "default": false, + "description": "Supports tool/function calling" + }, + "prompts": { + "type": "boolean", + "default": false, + "description": "Supports prompt templates" + }, + "sampling": { + "type": "boolean", + "default": false, + "description": "Supports sampling from LLMs" + }, + "logging": { + "type": "boolean", + "default": false, + "description": "Supports logging and debugging" + } + }, + "additionalProperties": false + }, + "protocolVersion": { + "type": "string", + "default": "2024-11-05", + "description": "MCP protocol version" + }, + "vendor": { + "type": "string", + "description": "Server vendor/provider" + }, + "homepage": { + "type": "string", + "format": "uri", + "description": "Server homepage URL" + }, + "documentation": { + "type": "string", + "format": "uri", + "description": "Documentation URL" + } + }, + "required": [ + "name", + "version", + "capabilities" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/ai/MCPTool.json b/packages/spec/json-schema/ai/MCPTool.json new file mode 100644 index 000000000..c14b528b0 --- /dev/null +++ b/packages/spec/json-schema/ai/MCPTool.json @@ -0,0 +1,266 @@ +{ + "$ref": "#/definitions/MCPTool", + "definitions": { + "MCPTool": { + "type": "object", + "properties": { + "name": { + "type": "string", + "pattern": "^[a-z_][a-z0-9_]*$", + "description": "Tool function name (snake_case)" + }, + "description": { + "type": "string", + "description": "Tool description for AI consumption (be detailed and specific)" + }, + "parameters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Parameter name" + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array" + ] + }, + "description": { + "type": "string", + "description": "Parameter description for AI consumption" + }, + "required": { + "type": "boolean", + "default": false + }, + "default": {}, + "enum": { + "type": "array", + "items": {}, + "description": "Allowed values" + }, + "pattern": { + "type": "string", + "description": "Regex validation pattern (for strings)" + }, + "minimum": { + "type": "number", + "description": "Minimum value (for numbers)" + }, + "maximum": { + "type": "number", + "description": "Maximum value (for numbers)" + }, + "minLength": { + "type": "integer", + "minimum": 0, + "description": "Minimum length (for strings/arrays)" + }, + "maxLength": { + "type": "integer", + "minimum": 0, + "description": "Maximum length (for strings/arrays)" + }, + "properties": { + "type": "object", + "additionalProperties": {}, + "description": "Properties for object types" + }, + "items": { + "description": "Item schema for array types" + } + }, + "required": [ + "name", + "type", + "description" + ], + "additionalProperties": false + }, + "description": "Tool parameters" + }, + "returns": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array", + "void" + ] + }, + "description": { + "type": "string" + }, + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Parameter name" + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array" + ] + }, + "description": { + "type": "string", + "description": "Parameter description for AI consumption" + }, + "required": { + "type": "boolean", + "default": false + }, + "default": {}, + "enum": { + "type": "array", + "items": {}, + "description": "Allowed values" + }, + "pattern": { + "type": "string", + "description": "Regex validation pattern (for strings)" + }, + "minimum": { + "type": "number", + "description": "Minimum value (for numbers)" + }, + "maximum": { + "type": "number", + "description": "Maximum value (for numbers)" + }, + "minLength": { + "type": "integer", + "minimum": 0, + "description": "Minimum length (for strings/arrays)" + }, + "maxLength": { + "type": "integer", + "minimum": 0, + "description": "Maximum length (for strings/arrays)" + }, + "properties": { + "type": "object", + "additionalProperties": {}, + "description": "Properties for object types" + }, + "items": { + "description": "Item schema for array types" + } + }, + "required": [ + "name", + "type", + "description" + ], + "additionalProperties": false, + "description": "Return value schema" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + "handler": { + "type": "string", + "description": "Handler function or endpoint reference" + }, + "async": { + "type": "boolean", + "default": true, + "description": "Whether the tool executes asynchronously" + }, + "timeout": { + "type": "integer", + "exclusiveMinimum": 0, + "description": "Execution timeout in milliseconds" + }, + "sideEffects": { + "type": "string", + "enum": [ + "none", + "read", + "write", + "delete" + ], + "default": "read", + "description": "Tool side effects" + }, + "requiresConfirmation": { + "type": "boolean", + "default": false, + "description": "Require user confirmation before execution" + }, + "confirmationMessage": { + "type": "string" + }, + "examples": { + "type": "array", + "items": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "parameters": { + "type": "object", + "additionalProperties": {} + }, + "result": {} + }, + "required": [ + "description", + "parameters" + ], + "additionalProperties": false + }, + "description": "Usage examples for AI learning" + }, + "category": { + "type": "string", + "description": "Tool category (e.g., \"data\", \"workflow\", \"analytics\")" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "deprecated": { + "type": "boolean", + "default": false + }, + "version": { + "type": "string", + "default": "1.0.0" + } + }, + "required": [ + "name", + "description", + "parameters", + "handler" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/ai/MCPToolCallRequest.json b/packages/spec/json-schema/ai/MCPToolCallRequest.json new file mode 100644 index 000000000..1e5628846 --- /dev/null +++ b/packages/spec/json-schema/ai/MCPToolCallRequest.json @@ -0,0 +1,52 @@ +{ + "$ref": "#/definitions/MCPToolCallRequest", + "definitions": { + "MCPToolCallRequest": { + "type": "object", + "properties": { + "toolName": { + "type": "string", + "description": "Tool to invoke" + }, + "parameters": { + "type": "object", + "additionalProperties": {}, + "description": "Tool parameters" + }, + "timeout": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "confirmationProvided": { + "type": "boolean", + "description": "User confirmation for tools that require it" + }, + "context": { + "type": "object", + "properties": { + "userId": { + "type": "string" + }, + "sessionId": { + "type": "string" + }, + "agentName": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + } + }, + "additionalProperties": false + } + }, + "required": [ + "toolName", + "parameters" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/ai/MCPToolCallResponse.json b/packages/spec/json-schema/ai/MCPToolCallResponse.json new file mode 100644 index 000000000..de5a1e07b --- /dev/null +++ b/packages/spec/json-schema/ai/MCPToolCallResponse.json @@ -0,0 +1,57 @@ +{ + "$ref": "#/definitions/MCPToolCallResponse", + "definitions": { + "MCPToolCallResponse": { + "type": "object", + "properties": { + "toolName": { + "type": "string" + }, + "status": { + "type": "string", + "enum": [ + "success", + "error", + "timeout", + "cancelled" + ] + }, + "result": { + "description": "Tool execution result" + }, + "error": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "details": {} + }, + "required": [ + "code", + "message" + ], + "additionalProperties": false + }, + "executionTime": { + "type": "number", + "minimum": 0, + "description": "Execution time in milliseconds" + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "toolName", + "status" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/ai/MCPToolParameter.json b/packages/spec/json-schema/ai/MCPToolParameter.json new file mode 100644 index 000000000..edf77c921 --- /dev/null +++ b/packages/spec/json-schema/ai/MCPToolParameter.json @@ -0,0 +1,75 @@ +{ + "$ref": "#/definitions/MCPToolParameter", + "definitions": { + "MCPToolParameter": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Parameter name" + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "object", + "array" + ] + }, + "description": { + "type": "string", + "description": "Parameter description for AI consumption" + }, + "required": { + "type": "boolean", + "default": false + }, + "default": {}, + "enum": { + "type": "array", + "items": {}, + "description": "Allowed values" + }, + "pattern": { + "type": "string", + "description": "Regex validation pattern (for strings)" + }, + "minimum": { + "type": "number", + "description": "Minimum value (for numbers)" + }, + "maximum": { + "type": "number", + "description": "Maximum value (for numbers)" + }, + "minLength": { + "type": "integer", + "minimum": 0, + "description": "Minimum length (for strings/arrays)" + }, + "maxLength": { + "type": "integer", + "minimum": 0, + "description": "Maximum length (for strings/arrays)" + }, + "properties": { + "type": "object", + "additionalProperties": {}, + "description": "Properties for object types" + }, + "items": { + "description": "Item schema for array types" + } + }, + "required": [ + "name", + "type", + "description" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/ai/MCPTransportConfig.json b/packages/spec/json-schema/ai/MCPTransportConfig.json new file mode 100644 index 000000000..3f84ff025 --- /dev/null +++ b/packages/spec/json-schema/ai/MCPTransportConfig.json @@ -0,0 +1,105 @@ +{ + "$ref": "#/definitions/MCPTransportConfig", + "definitions": { + "MCPTransportConfig": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "stdio", + "http", + "websocket", + "grpc" + ] + }, + "url": { + "type": "string", + "format": "uri", + "description": "Server URL (for HTTP/WebSocket/gRPC)" + }, + "headers": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom headers for requests" + }, + "auth": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "none", + "bearer", + "api_key", + "oauth2", + "custom" + ], + "default": "none" + }, + "token": { + "type": "string", + "description": "Bearer token or API key" + }, + "secretRef": { + "type": "string", + "description": "Reference to stored secret" + }, + "headerName": { + "type": "string", + "description": "Custom auth header name" + } + }, + "additionalProperties": false + }, + "timeout": { + "type": "integer", + "exclusiveMinimum": 0, + "default": 30000, + "description": "Request timeout in milliseconds" + }, + "retryAttempts": { + "type": "integer", + "minimum": 0, + "maximum": 5, + "default": 3 + }, + "retryDelay": { + "type": "integer", + "exclusiveMinimum": 0, + "default": 1000, + "description": "Delay between retries in milliseconds" + }, + "command": { + "type": "string", + "description": "Command to execute (for stdio transport)" + }, + "args": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Command arguments" + }, + "env": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Environment variables" + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the process" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/ai/MCPTransportType.json b/packages/spec/json-schema/ai/MCPTransportType.json new file mode 100644 index 000000000..ac71ee977 --- /dev/null +++ b/packages/spec/json-schema/ai/MCPTransportType.json @@ -0,0 +1,15 @@ +{ + "$ref": "#/definitions/MCPTransportType", + "definitions": { + "MCPTransportType": { + "type": "string", + "enum": [ + "stdio", + "http", + "websocket", + "grpc" + ] + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/api/ApiCapabilities.json b/packages/spec/json-schema/api/ApiCapabilities.json index 106516172..359a684ce 100644 --- a/packages/spec/json-schema/api/ApiCapabilities.json +++ b/packages/spec/json-schema/api/ApiCapabilities.json @@ -29,6 +29,26 @@ "type": "boolean", "default": false, "description": "Is Hub management enabled?" + }, + "ai": { + "type": "boolean", + "default": false, + "description": "Is the AI engine enabled?" + }, + "workflow": { + "type": "boolean", + "default": false, + "description": "Is the Workflow engine enabled?" + }, + "notifications": { + "type": "boolean", + "default": false, + "description": "Is the Notification service enabled?" + }, + "i18n": { + "type": "boolean", + "default": false, + "description": "Is the i18n service enabled?" } }, "additionalProperties": false diff --git a/packages/spec/json-schema/api/ApiRoutes.json b/packages/spec/json-schema/api/ApiRoutes.json index b0f62b890..081cf3c87 100644 --- a/packages/spec/json-schema/api/ApiRoutes.json +++ b/packages/spec/json-schema/api/ApiRoutes.json @@ -6,39 +6,63 @@ "properties": { "data": { "type": "string", - "description": "e.g. /api/data" + "description": "e.g. /api/v1/data" }, "metadata": { "type": "string", - "description": "e.g. /api/meta" + "description": "e.g. /api/v1/meta" }, "ui": { "type": "string", - "description": "e.g. /api/ui" + "description": "e.g. /api/v1/ui" }, "auth": { "type": "string", - "description": "e.g. /api/auth" + "description": "e.g. /api/v1/auth" }, "automation": { "type": "string", - "description": "e.g. /api/automation" + "description": "e.g. /api/v1/automation" }, "storage": { "type": "string", - "description": "e.g. /api/storage" + "description": "e.g. /api/v1/storage" }, "analytics": { "type": "string", - "description": "e.g. /api/analytics" + "description": "e.g. /api/v1/analytics" }, "hub": { "type": "string", - "description": "e.g. /api/hub" + "description": "e.g. /api/v1/hub" }, "graphql": { "type": "string", "description": "e.g. /graphql" + }, + "packages": { + "type": "string", + "description": "e.g. /api/v1/packages" + }, + "workflow": { + "type": "string", + "description": "e.g. /api/v1/workflow" + }, + "realtime": { + "type": "string", + "description": "e.g. /api/v1/realtime" + }, + "notifications": { + "type": "string", + "description": "e.g. /api/v1/notifications" + }, + "ai": { + "type": "string", + "description": "e.g. /api/v1/ai" + }, + "i18n": { + "type": "string", + "description": "e.g. /api/v1/i18n" } }, "required": [ diff --git a/packages/spec/json-schema/api/CompileManifestResponse.json b/packages/spec/json-schema/api/CompileManifestResponse.json index 491da6630..0c48c423d 100644 --- a/packages/spec/json-schema/api/CompileManifestResponse.json +++ b/packages/spec/json-schema/api/CompileManifestResponse.json @@ -412,6 +412,36 @@ "additionalProperties": false }, "description": "Query Function contributions" + }, + "routes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "prefix": { + "type": "string", + "pattern": "^\\/", + "description": "API path prefix" + }, + "service": { + "type": "string", + "description": "Service name this plugin provides" + }, + "methods": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Protocol method names implemented (e.g. [\"aiNlq\", \"aiChat\"])" + } + }, + "required": [ + "prefix", + "service" + ], + "additionalProperties": false + }, + "description": "API route contributions to HttpDispatcher" } }, "additionalProperties": false, diff --git a/packages/spec/json-schema/api/DisablePackageResponse.json b/packages/spec/json-schema/api/DisablePackageResponse.json index e1210367b..619d469a7 100644 --- a/packages/spec/json-schema/api/DisablePackageResponse.json +++ b/packages/spec/json-schema/api/DisablePackageResponse.json @@ -353,6 +353,36 @@ "additionalProperties": false }, "description": "Query Function contributions" + }, + "routes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "prefix": { + "type": "string", + "pattern": "^\\/", + "description": "API path prefix" + }, + "service": { + "type": "string", + "description": "Service name this plugin provides" + }, + "methods": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Protocol method names implemented (e.g. [\"aiNlq\", \"aiChat\"])" + } + }, + "required": [ + "prefix", + "service" + ], + "additionalProperties": false + }, + "description": "API route contributions to HttpDispatcher" } }, "additionalProperties": false, diff --git a/packages/spec/json-schema/api/Discovery.json b/packages/spec/json-schema/api/Discovery.json index b7a62fa46..90d5f255a 100644 --- a/packages/spec/json-schema/api/Discovery.json +++ b/packages/spec/json-schema/api/Discovery.json @@ -23,39 +23,63 @@ "properties": { "data": { "type": "string", - "description": "e.g. /api/data" + "description": "e.g. /api/v1/data" }, "metadata": { "type": "string", - "description": "e.g. /api/meta" + "description": "e.g. /api/v1/meta" }, "ui": { "type": "string", - "description": "e.g. /api/ui" + "description": "e.g. /api/v1/ui" }, "auth": { "type": "string", - "description": "e.g. /api/auth" + "description": "e.g. /api/v1/auth" }, "automation": { "type": "string", - "description": "e.g. /api/automation" + "description": "e.g. /api/v1/automation" }, "storage": { "type": "string", - "description": "e.g. /api/storage" + "description": "e.g. /api/v1/storage" }, "analytics": { "type": "string", - "description": "e.g. /api/analytics" + "description": "e.g. /api/v1/analytics" }, "hub": { "type": "string", - "description": "e.g. /api/hub" + "description": "e.g. /api/v1/hub" }, "graphql": { "type": "string", "description": "e.g. /graphql" + }, + "packages": { + "type": "string", + "description": "e.g. /api/v1/packages" + }, + "workflow": { + "type": "string", + "description": "e.g. /api/v1/workflow" + }, + "realtime": { + "type": "string", + "description": "e.g. /api/v1/realtime" + }, + "notifications": { + "type": "string", + "description": "e.g. /api/v1/notifications" + }, + "ai": { + "type": "string", + "description": "e.g. /api/v1/ai" + }, + "i18n": { + "type": "string", + "description": "e.g. /api/v1/i18n" } }, "required": [ @@ -93,6 +117,26 @@ "type": "boolean", "default": false, "description": "Is Hub management enabled?" + }, + "ai": { + "type": "boolean", + "default": false, + "description": "Is the AI engine enabled?" + }, + "workflow": { + "type": "boolean", + "default": false, + "description": "Is the Workflow engine enabled?" + }, + "notifications": { + "type": "boolean", + "default": false, + "description": "Is the Notification service enabled?" + }, + "i18n": { + "type": "boolean", + "default": false, + "description": "Is the i18n service enabled?" } }, "additionalProperties": false diff --git a/packages/spec/json-schema/api/DispatcherConfig.json b/packages/spec/json-schema/api/DispatcherConfig.json new file mode 100644 index 000000000..58b821b73 --- /dev/null +++ b/packages/spec/json-schema/api/DispatcherConfig.json @@ -0,0 +1,95 @@ +{ + "$ref": "#/definitions/DispatcherConfig", + "definitions": { + "DispatcherConfig": { + "type": "object", + "properties": { + "routes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "prefix": { + "type": "string", + "pattern": "^\\/", + "description": "URL path prefix for routing (e.g. /api/v1/data)" + }, + "service": { + "type": "string", + "enum": [ + "metadata", + "data", + "auth", + "file-storage", + "search", + "cache", + "queue", + "automation", + "graphql", + "analytics", + "hub", + "realtime", + "job", + "notification", + "ai", + "i18n", + "ui", + "workflow" + ], + "description": "Target core service name" + }, + "authRequired": { + "type": "boolean", + "default": true, + "description": "Whether authentication is required" + }, + "criticality": { + "type": "string", + "enum": [ + "required", + "core", + "optional" + ], + "default": "optional", + "description": "Service criticality level for unavailability handling" + }, + "permissions": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Required permissions for this route namespace" + } + }, + "required": [ + "prefix", + "service" + ], + "additionalProperties": false + }, + "description": "Route-to-service mappings" + }, + "fallback": { + "type": "string", + "enum": [ + "404", + "proxy", + "custom" + ], + "default": "404", + "description": "Behavior when no route matches" + }, + "proxyTarget": { + "type": "string", + "format": "uri", + "description": "Proxy target URL when fallback is \"proxy\"" + } + }, + "required": [ + "routes" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/api/DispatcherRoute.json b/packages/spec/json-schema/api/DispatcherRoute.json new file mode 100644 index 000000000..2bbd85ff3 --- /dev/null +++ b/packages/spec/json-schema/api/DispatcherRoute.json @@ -0,0 +1,67 @@ +{ + "$ref": "#/definitions/DispatcherRoute", + "definitions": { + "DispatcherRoute": { + "type": "object", + "properties": { + "prefix": { + "type": "string", + "pattern": "^\\/", + "description": "URL path prefix for routing (e.g. /api/v1/data)" + }, + "service": { + "type": "string", + "enum": [ + "metadata", + "data", + "auth", + "file-storage", + "search", + "cache", + "queue", + "automation", + "graphql", + "analytics", + "hub", + "realtime", + "job", + "notification", + "ai", + "i18n", + "ui", + "workflow" + ], + "description": "Target core service name" + }, + "authRequired": { + "type": "boolean", + "default": true, + "description": "Whether authentication is required" + }, + "criticality": { + "type": "string", + "enum": [ + "required", + "core", + "optional" + ], + "default": "optional", + "description": "Service criticality level for unavailability handling" + }, + "permissions": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Required permissions for this route namespace" + } + }, + "required": [ + "prefix", + "service" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/api/EnablePackageResponse.json b/packages/spec/json-schema/api/EnablePackageResponse.json index 2c0f74757..10c295192 100644 --- a/packages/spec/json-schema/api/EnablePackageResponse.json +++ b/packages/spec/json-schema/api/EnablePackageResponse.json @@ -353,6 +353,36 @@ "additionalProperties": false }, "description": "Query Function contributions" + }, + "routes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "prefix": { + "type": "string", + "pattern": "^\\/", + "description": "API path prefix" + }, + "service": { + "type": "string", + "description": "Service name this plugin provides" + }, + "methods": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Protocol method names implemented (e.g. [\"aiNlq\", \"aiChat\"])" + } + }, + "required": [ + "prefix", + "service" + ], + "additionalProperties": false + }, + "description": "API route contributions to HttpDispatcher" } }, "additionalProperties": false, diff --git a/packages/spec/json-schema/api/GetDiscoveryResponse.json b/packages/spec/json-schema/api/GetDiscoveryResponse.json index 2ec6284f2..b573f32fa 100644 --- a/packages/spec/json-schema/api/GetDiscoveryResponse.json +++ b/packages/spec/json-schema/api/GetDiscoveryResponse.json @@ -40,6 +40,26 @@ "type": "boolean", "default": false, "description": "Is Hub management enabled?" + }, + "ai": { + "type": "boolean", + "default": false, + "description": "Is the AI engine enabled?" + }, + "workflow": { + "type": "boolean", + "default": false, + "description": "Is the Workflow engine enabled?" + }, + "notifications": { + "type": "boolean", + "default": false, + "description": "Is the Notification service enabled?" + }, + "i18n": { + "type": "boolean", + "default": false, + "description": "Is the i18n service enabled?" } }, "additionalProperties": false, @@ -50,39 +70,63 @@ "properties": { "data": { "type": "string", - "description": "e.g. /api/data" + "description": "e.g. /api/v1/data" }, "metadata": { "type": "string", - "description": "e.g. /api/meta" + "description": "e.g. /api/v1/meta" }, "ui": { "type": "string", - "description": "e.g. /api/ui" + "description": "e.g. /api/v1/ui" }, "auth": { "type": "string", - "description": "e.g. /api/auth" + "description": "e.g. /api/v1/auth" }, "automation": { "type": "string", - "description": "e.g. /api/automation" + "description": "e.g. /api/v1/automation" }, "storage": { "type": "string", - "description": "e.g. /api/storage" + "description": "e.g. /api/v1/storage" }, "analytics": { "type": "string", - "description": "e.g. /api/analytics" + "description": "e.g. /api/v1/analytics" }, "hub": { "type": "string", - "description": "e.g. /api/hub" + "description": "e.g. /api/v1/hub" }, "graphql": { "type": "string", "description": "e.g. /graphql" + }, + "packages": { + "type": "string", + "description": "e.g. /api/v1/packages" + }, + "workflow": { + "type": "string", + "description": "e.g. /api/v1/workflow" + }, + "realtime": { + "type": "string", + "description": "e.g. /api/v1/realtime" + }, + "notifications": { + "type": "string", + "description": "e.g. /api/v1/notifications" + }, + "ai": { + "type": "string", + "description": "e.g. /api/v1/ai" + }, + "i18n": { + "type": "string", + "description": "e.g. /api/v1/i18n" } }, "required": [ diff --git a/packages/spec/json-schema/api/GetPackageResponse.json b/packages/spec/json-schema/api/GetPackageResponse.json index e01ec941c..ed2321f39 100644 --- a/packages/spec/json-schema/api/GetPackageResponse.json +++ b/packages/spec/json-schema/api/GetPackageResponse.json @@ -353,6 +353,36 @@ "additionalProperties": false }, "description": "Query Function contributions" + }, + "routes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "prefix": { + "type": "string", + "pattern": "^\\/", + "description": "API path prefix" + }, + "service": { + "type": "string", + "description": "Service name this plugin provides" + }, + "methods": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Protocol method names implemented (e.g. [\"aiNlq\", \"aiChat\"])" + } + }, + "required": [ + "prefix", + "service" + ], + "additionalProperties": false + }, + "description": "API route contributions to HttpDispatcher" } }, "additionalProperties": false, diff --git a/packages/spec/json-schema/api/InstallPackageRequest.json b/packages/spec/json-schema/api/InstallPackageRequest.json index f59a63903..dd5703724 100644 --- a/packages/spec/json-schema/api/InstallPackageRequest.json +++ b/packages/spec/json-schema/api/InstallPackageRequest.json @@ -350,6 +350,36 @@ "additionalProperties": false }, "description": "Query Function contributions" + }, + "routes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "prefix": { + "type": "string", + "pattern": "^\\/", + "description": "API path prefix" + }, + "service": { + "type": "string", + "description": "Service name this plugin provides" + }, + "methods": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Protocol method names implemented (e.g. [\"aiNlq\", \"aiChat\"])" + } + }, + "required": [ + "prefix", + "service" + ], + "additionalProperties": false + }, + "description": "API route contributions to HttpDispatcher" } }, "additionalProperties": false, diff --git a/packages/spec/json-schema/api/InstallPackageResponse.json b/packages/spec/json-schema/api/InstallPackageResponse.json index 5ecbbce5d..543ffd95a 100644 --- a/packages/spec/json-schema/api/InstallPackageResponse.json +++ b/packages/spec/json-schema/api/InstallPackageResponse.json @@ -353,6 +353,36 @@ "additionalProperties": false }, "description": "Query Function contributions" + }, + "routes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "prefix": { + "type": "string", + "pattern": "^\\/", + "description": "API path prefix" + }, + "service": { + "type": "string", + "description": "Service name this plugin provides" + }, + "methods": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Protocol method names implemented (e.g. [\"aiNlq\", \"aiChat\"])" + } + }, + "required": [ + "prefix", + "service" + ], + "additionalProperties": false + }, + "description": "API route contributions to HttpDispatcher" } }, "additionalProperties": false, diff --git a/packages/spec/json-schema/api/ListPackagesResponse.json b/packages/spec/json-schema/api/ListPackagesResponse.json index ef65e9e5b..bd7e8c8e6 100644 --- a/packages/spec/json-schema/api/ListPackagesResponse.json +++ b/packages/spec/json-schema/api/ListPackagesResponse.json @@ -355,6 +355,36 @@ "additionalProperties": false }, "description": "Query Function contributions" + }, + "routes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "prefix": { + "type": "string", + "pattern": "^\\/", + "description": "API path prefix" + }, + "service": { + "type": "string", + "description": "Service name this plugin provides" + }, + "methods": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Protocol method names implemented (e.g. [\"aiNlq\", \"aiChat\"])" + } + }, + "required": [ + "prefix", + "service" + ], + "additionalProperties": false + }, + "description": "API route contributions to HttpDispatcher" } }, "additionalProperties": false, diff --git a/packages/spec/json-schema/hub/ComposerResponse.json b/packages/spec/json-schema/hub/ComposerResponse.json index 8312bc5c6..148eba506 100644 --- a/packages/spec/json-schema/hub/ComposerResponse.json +++ b/packages/spec/json-schema/hub/ComposerResponse.json @@ -353,6 +353,36 @@ "additionalProperties": false }, "description": "Query Function contributions" + }, + "routes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "prefix": { + "type": "string", + "pattern": "^\\/", + "description": "API path prefix" + }, + "service": { + "type": "string", + "description": "Service name this plugin provides" + }, + "methods": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Protocol method names implemented (e.g. [\"aiNlq\", \"aiChat\"])" + } + }, + "required": [ + "prefix", + "service" + ], + "additionalProperties": false + }, + "description": "API route contributions to HttpDispatcher" } }, "additionalProperties": false, diff --git a/packages/spec/json-schema/kernel/DisablePackageResponse.json b/packages/spec/json-schema/kernel/DisablePackageResponse.json index e1210367b..619d469a7 100644 --- a/packages/spec/json-schema/kernel/DisablePackageResponse.json +++ b/packages/spec/json-schema/kernel/DisablePackageResponse.json @@ -353,6 +353,36 @@ "additionalProperties": false }, "description": "Query Function contributions" + }, + "routes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "prefix": { + "type": "string", + "pattern": "^\\/", + "description": "API path prefix" + }, + "service": { + "type": "string", + "description": "Service name this plugin provides" + }, + "methods": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Protocol method names implemented (e.g. [\"aiNlq\", \"aiChat\"])" + } + }, + "required": [ + "prefix", + "service" + ], + "additionalProperties": false + }, + "description": "API route contributions to HttpDispatcher" } }, "additionalProperties": false, diff --git a/packages/spec/json-schema/kernel/EnablePackageResponse.json b/packages/spec/json-schema/kernel/EnablePackageResponse.json index 2c0f74757..10c295192 100644 --- a/packages/spec/json-schema/kernel/EnablePackageResponse.json +++ b/packages/spec/json-schema/kernel/EnablePackageResponse.json @@ -353,6 +353,36 @@ "additionalProperties": false }, "description": "Query Function contributions" + }, + "routes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "prefix": { + "type": "string", + "pattern": "^\\/", + "description": "API path prefix" + }, + "service": { + "type": "string", + "description": "Service name this plugin provides" + }, + "methods": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Protocol method names implemented (e.g. [\"aiNlq\", \"aiChat\"])" + } + }, + "required": [ + "prefix", + "service" + ], + "additionalProperties": false + }, + "description": "API route contributions to HttpDispatcher" } }, "additionalProperties": false, diff --git a/packages/spec/json-schema/kernel/GetPackageResponse.json b/packages/spec/json-schema/kernel/GetPackageResponse.json index e01ec941c..ed2321f39 100644 --- a/packages/spec/json-schema/kernel/GetPackageResponse.json +++ b/packages/spec/json-schema/kernel/GetPackageResponse.json @@ -353,6 +353,36 @@ "additionalProperties": false }, "description": "Query Function contributions" + }, + "routes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "prefix": { + "type": "string", + "pattern": "^\\/", + "description": "API path prefix" + }, + "service": { + "type": "string", + "description": "Service name this plugin provides" + }, + "methods": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Protocol method names implemented (e.g. [\"aiNlq\", \"aiChat\"])" + } + }, + "required": [ + "prefix", + "service" + ], + "additionalProperties": false + }, + "description": "API route contributions to HttpDispatcher" } }, "additionalProperties": false, diff --git a/packages/spec/json-schema/kernel/InstallPackageRequest.json b/packages/spec/json-schema/kernel/InstallPackageRequest.json index f59a63903..dd5703724 100644 --- a/packages/spec/json-schema/kernel/InstallPackageRequest.json +++ b/packages/spec/json-schema/kernel/InstallPackageRequest.json @@ -350,6 +350,36 @@ "additionalProperties": false }, "description": "Query Function contributions" + }, + "routes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "prefix": { + "type": "string", + "pattern": "^\\/", + "description": "API path prefix" + }, + "service": { + "type": "string", + "description": "Service name this plugin provides" + }, + "methods": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Protocol method names implemented (e.g. [\"aiNlq\", \"aiChat\"])" + } + }, + "required": [ + "prefix", + "service" + ], + "additionalProperties": false + }, + "description": "API route contributions to HttpDispatcher" } }, "additionalProperties": false, diff --git a/packages/spec/json-schema/kernel/InstallPackageResponse.json b/packages/spec/json-schema/kernel/InstallPackageResponse.json index 5ecbbce5d..543ffd95a 100644 --- a/packages/spec/json-schema/kernel/InstallPackageResponse.json +++ b/packages/spec/json-schema/kernel/InstallPackageResponse.json @@ -353,6 +353,36 @@ "additionalProperties": false }, "description": "Query Function contributions" + }, + "routes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "prefix": { + "type": "string", + "pattern": "^\\/", + "description": "API path prefix" + }, + "service": { + "type": "string", + "description": "Service name this plugin provides" + }, + "methods": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Protocol method names implemented (e.g. [\"aiNlq\", \"aiChat\"])" + } + }, + "required": [ + "prefix", + "service" + ], + "additionalProperties": false + }, + "description": "API route contributions to HttpDispatcher" } }, "additionalProperties": false, diff --git a/packages/spec/json-schema/kernel/InstalledPackage.json b/packages/spec/json-schema/kernel/InstalledPackage.json index f12e13a71..aeba69477 100644 --- a/packages/spec/json-schema/kernel/InstalledPackage.json +++ b/packages/spec/json-schema/kernel/InstalledPackage.json @@ -350,6 +350,36 @@ "additionalProperties": false }, "description": "Query Function contributions" + }, + "routes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "prefix": { + "type": "string", + "pattern": "^\\/", + "description": "API path prefix" + }, + "service": { + "type": "string", + "description": "Service name this plugin provides" + }, + "methods": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Protocol method names implemented (e.g. [\"aiNlq\", \"aiChat\"])" + } + }, + "required": [ + "prefix", + "service" + ], + "additionalProperties": false + }, + "description": "API route contributions to HttpDispatcher" } }, "additionalProperties": false, diff --git a/packages/spec/json-schema/kernel/ListPackagesResponse.json b/packages/spec/json-schema/kernel/ListPackagesResponse.json index ef65e9e5b..bd7e8c8e6 100644 --- a/packages/spec/json-schema/kernel/ListPackagesResponse.json +++ b/packages/spec/json-schema/kernel/ListPackagesResponse.json @@ -355,6 +355,36 @@ "additionalProperties": false }, "description": "Query Function contributions" + }, + "routes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "prefix": { + "type": "string", + "pattern": "^\\/", + "description": "API path prefix" + }, + "service": { + "type": "string", + "description": "Service name this plugin provides" + }, + "methods": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Protocol method names implemented (e.g. [\"aiNlq\", \"aiChat\"])" + } + }, + "required": [ + "prefix", + "service" + ], + "additionalProperties": false + }, + "description": "API route contributions to HttpDispatcher" } }, "additionalProperties": false, diff --git a/packages/spec/json-schema/kernel/Manifest.json b/packages/spec/json-schema/kernel/Manifest.json index c9a922ebc..d1b64439a 100644 --- a/packages/spec/json-schema/kernel/Manifest.json +++ b/packages/spec/json-schema/kernel/Manifest.json @@ -347,6 +347,36 @@ "additionalProperties": false }, "description": "Query Function contributions" + }, + "routes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "prefix": { + "type": "string", + "pattern": "^\\/", + "description": "API path prefix" + }, + "service": { + "type": "string", + "description": "Service name this plugin provides" + }, + "methods": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Protocol method names implemented (e.g. [\"aiNlq\", \"aiChat\"])" + } + }, + "required": [ + "prefix", + "service" + ], + "additionalProperties": false + }, + "description": "API route contributions to HttpDispatcher" } }, "additionalProperties": false, diff --git a/packages/spec/json-schema/system/CoreServiceName.json b/packages/spec/json-schema/system/CoreServiceName.json index e61294170..8b46866f4 100644 --- a/packages/spec/json-schema/system/CoreServiceName.json +++ b/packages/spec/json-schema/system/CoreServiceName.json @@ -17,7 +17,11 @@ "hub", "realtime", "job", - "notification" + "notification", + "ai", + "i18n", + "ui", + "workflow" ] } }, diff --git a/packages/spec/json-schema/system/KernelServiceMap.json b/packages/spec/json-schema/system/KernelServiceMap.json index 2a8a6717a..27b879515 100644 --- a/packages/spec/json-schema/system/KernelServiceMap.json +++ b/packages/spec/json-schema/system/KernelServiceMap.json @@ -21,7 +21,11 @@ "hub", "realtime", "job", - "notification" + "notification", + "ai", + "i18n", + "ui", + "workflow" ] } } diff --git a/packages/spec/json-schema/system/ServiceConfig.json b/packages/spec/json-schema/system/ServiceConfig.json index f425cb9f2..c2e81bafb 100644 --- a/packages/spec/json-schema/system/ServiceConfig.json +++ b/packages/spec/json-schema/system/ServiceConfig.json @@ -23,7 +23,11 @@ "hub", "realtime", "job", - "notification" + "notification", + "ai", + "i18n", + "ui", + "workflow" ] }, "options": { diff --git a/packages/spec/json-schema/system/ServiceStatus.json b/packages/spec/json-schema/system/ServiceStatus.json index 2e30cfc76..ed6dc3988 100644 --- a/packages/spec/json-schema/system/ServiceStatus.json +++ b/packages/spec/json-schema/system/ServiceStatus.json @@ -20,7 +20,11 @@ "hub", "realtime", "job", - "notification" + "notification", + "ai", + "i18n", + "ui", + "workflow" ] }, "enabled": { diff --git a/packages/spec/src/ai/index.ts b/packages/spec/src/ai/index.ts index 8350c0044..5be304e2c 100644 --- a/packages/spec/src/ai/index.ts +++ b/packages/spec/src/ai/index.ts @@ -5,6 +5,7 @@ * - Agent Configuration * - DevOps Agent (Self-iterating Development) * - Model Registry & Selection + * - Model Context Protocol (MCP) * - RAG Pipeline * - Natural Language Query (NLQ) * - Workflow Automation @@ -21,6 +22,7 @@ export * from './devops-agent.zod'; export * from './plugin-development.zod'; export * from './runtime-ops.zod'; export * from './model-registry.zod'; +export * from './mcp.zod'; export * from './rag-pipeline.zod'; export * from './nlq.zod'; export * from './orchestration.zod'; diff --git a/packages/spec/src/ai/mcp.test.ts b/packages/spec/src/ai/mcp.test.ts new file mode 100644 index 000000000..4a73e3124 --- /dev/null +++ b/packages/spec/src/ai/mcp.test.ts @@ -0,0 +1,594 @@ +import { describe, it, expect } from 'vitest'; +import { + MCPServerConfigSchema, + MCPToolSchema, + MCPResourceSchema, + MCPPromptSchema, + MCPTransportConfigSchema, + MCPServerInfoSchema, + MCPToolCallRequestSchema, + MCPToolCallResponseSchema, + MCPResourceRequestSchema, + MCPPromptRequestSchema, + type MCPServerConfig, + type MCPTool, + type MCPResource, +} from './mcp.zod'; + +describe('MCPTransportConfigSchema', () => { + it('should accept stdio transport', () => { + const transport = { + type: 'stdio' as const, + command: 'node', + args: ['mcp-server.js'], + }; + + const result = MCPTransportConfigSchema.parse(transport); + expect(result.type).toBe('stdio'); + expect(result.timeout).toBe(30000); + expect(result.retryAttempts).toBe(3); + }); + + it('should accept HTTP transport with auth', () => { + const transport = { + type: 'http' as const, + url: 'https://api.example.com/mcp', + auth: { + type: 'bearer' as const, + token: 'secret-token', + }, + headers: { + 'X-Custom-Header': 'value', + }, + }; + + expect(() => MCPTransportConfigSchema.parse(transport)).not.toThrow(); + }); + + it('should accept websocket transport', () => { + const transport = { + type: 'websocket' as const, + url: 'wss://api.example.com/mcp', + timeout: 60000, + }; + + expect(() => MCPTransportConfigSchema.parse(transport)).not.toThrow(); + }); + + it('should enforce URL for HTTP/WebSocket transport', () => { + const transport = { + type: 'http' as const, + url: 'https://api.example.com/mcp', + }; + + expect(() => MCPTransportConfigSchema.parse(transport)).not.toThrow(); + }); +}); + +describe('MCPResourceSchema', () => { + it('should accept minimal resource', () => { + const resource = { + uri: 'objectstack://objects/account', + name: 'Account List', + }; + + const result = MCPResourceSchema.parse(resource); + expect(result.resourceType).toBe('json'); + expect(result.cacheable).toBe(true); + }); + + it('should accept full resource definition', () => { + const resource = { + uri: 'objectstack://objects/account/ABC123', + name: 'Account ABC123', + description: 'Details for account ABC123', + mimeType: 'application/json', + resourceType: 'json' as const, + content: { + id: 'ABC123', + name: 'Acme Corp', + }, + size: 256, + lastModified: '2024-01-01T00:00:00Z', + tags: ['account', 'customer'], + permissions: { + read: true, + write: false, + delete: false, + }, + cacheable: true, + cacheMaxAge: 300, + }; + + expect(() => MCPResourceSchema.parse(resource)).not.toThrow(); + }); + + it('should accept all resource types', () => { + const types = ['text', 'json', 'binary', 'stream'] as const; + + types.forEach(resourceType => { + const resource = { + uri: `test://resource/${resourceType}`, + name: `Test ${resourceType}`, + resourceType, + }; + expect(() => MCPResourceSchema.parse(resource)).not.toThrow(); + }); + }); +}); + +describe('MCPToolSchema', () => { + it('should accept minimal tool', () => { + const tool = { + name: 'create_account', + description: 'Creates a new account in the system', + parameters: [], + handler: 'flows.create_account', + }; + + const result = MCPToolSchema.parse(tool); + expect(result.async).toBe(true); + expect(result.sideEffects).toBe('read'); + expect(result.requiresConfirmation).toBe(false); + expect(result.deprecated).toBe(false); + expect(result.version).toBe('1.0.0'); + }); + + it('should accept tool with parameters', () => { + const tool = { + name: 'search_records', + description: 'Search for records in an object', + parameters: [ + { + name: 'object_name', + type: 'string' as const, + description: 'Name of the object to search', + required: true, + }, + { + name: 'query', + type: 'string' as const, + description: 'Search query', + required: true, + minLength: 1, + maxLength: 500, + }, + { + name: 'limit', + type: 'number' as const, + description: 'Maximum number of results', + required: false, + default: 10, + minimum: 1, + maximum: 100, + }, + ], + handler: 'data.search', + sideEffects: 'read' as const, + }; + + expect(() => MCPToolSchema.parse(tool)).not.toThrow(); + }); + + it('should accept tool with return type', () => { + const tool = { + name: 'get_total_count', + description: 'Get total count of records', + parameters: [ + { + name: 'object_name', + type: 'string' as const, + description: 'Object name', + required: true, + }, + ], + returns: { + type: 'number' as const, + description: 'Total count of records', + }, + handler: 'data.count', + }; + + expect(() => MCPToolSchema.parse(tool)).not.toThrow(); + }); + + it('should accept tool with examples', () => { + const tool = { + name: 'create_task', + description: 'Create a new task', + parameters: [ + { + name: 'title', + type: 'string' as const, + description: 'Task title', + required: true, + }, + { + name: 'priority', + type: 'string' as const, + description: 'Task priority', + required: false, + enum: ['low', 'medium', 'high'], + default: 'medium', + }, + ], + handler: 'flows.create_task', + sideEffects: 'write' as const, + requiresConfirmation: true, + examples: [ + { + description: 'Create a high priority task', + parameters: { + title: 'Fix critical bug', + priority: 'high', + }, + result: { id: 'TASK-001', status: 'created' }, + }, + ], + }; + + expect(() => MCPToolSchema.parse(tool)).not.toThrow(); + }); + + it('should enforce snake_case naming', () => { + expect(() => MCPToolSchema.parse({ + name: 'CreateAccount', + description: 'Test', + parameters: [], + handler: 'test', + })).toThrow(); + + expect(() => MCPToolSchema.parse({ + name: 'create-account', + description: 'Test', + parameters: [], + handler: 'test', + })).toThrow(); + + expect(() => MCPToolSchema.parse({ + name: 'create_account', + description: 'Test', + parameters: [], + handler: 'test', + })).not.toThrow(); + }); + + it('should accept all side effect types', () => { + const sideEffects = ['none', 'read', 'write', 'delete'] as const; + + sideEffects.forEach(effect => { + const tool = { + name: 'test_tool', + description: 'Test tool', + parameters: [], + handler: 'test', + sideEffects: effect, + }; + expect(() => MCPToolSchema.parse(tool)).not.toThrow(); + }); + }); +}); + +describe('MCPPromptSchema', () => { + it('should accept minimal prompt', () => { + const prompt = { + name: 'summarize_ticket', + messages: [ + { + role: 'system' as const, + content: 'You are a helpful assistant that summarizes support tickets.', + }, + { + role: 'user' as const, + content: 'Please summarize this ticket: {{ticket_content}}', + }, + ], + }; + + const result = MCPPromptSchema.parse(prompt); + expect(result.version).toBe('1.0.0'); + }); + + it('should accept prompt with arguments', () => { + const prompt = { + name: 'generate_report', + description: 'Generate a report based on data', + messages: [ + { + role: 'system' as const, + content: 'You are a report generator.', + }, + { + role: 'user' as const, + content: 'Generate a {{report_type}} report for {{time_period}}', + }, + ], + arguments: [ + { + name: 'report_type', + type: 'string' as const, + required: true, + description: 'Type of report to generate', + }, + { + name: 'time_period', + type: 'string' as const, + required: true, + description: 'Time period for the report', + }, + ], + }; + + expect(() => MCPPromptSchema.parse(prompt)).not.toThrow(); + }); + + it('should enforce snake_case naming', () => { + expect(() => MCPPromptSchema.parse({ + name: 'GenerateReport', + messages: [{ role: 'user', content: 'test' }], + })).toThrow(); + + expect(() => MCPPromptSchema.parse({ + name: 'generate_report', + messages: [{ role: 'user', content: 'test' }], + })).not.toThrow(); + }); +}); + +describe('MCPServerInfoSchema', () => { + it('should accept minimal server info', () => { + const info = { + name: 'ObjectStack MCP Server', + version: '1.0.0', + capabilities: { + resources: true, + tools: true, + }, + }; + + const result = MCPServerInfoSchema.parse(info); + expect(result.protocolVersion).toBe('2024-11-05'); + }); + + it('should accept full server info', () => { + const info = { + name: 'ObjectStack MCP Server', + version: '1.2.3', + description: 'MCP server for ObjectStack integration', + capabilities: { + resources: true, + resourceTemplates: true, + tools: true, + prompts: true, + sampling: false, + logging: true, + }, + protocolVersion: '2024-11-05', + vendor: 'ObjectStack AI', + homepage: 'https://objectstack.ai', + documentation: 'https://docs.objectstack.ai/mcp', + }; + + expect(() => MCPServerInfoSchema.parse(info)).not.toThrow(); + }); +}); + +describe('MCPServerConfigSchema', () => { + it('should accept minimal server config', () => { + const config = { + name: 'objectstack_mcp', + label: 'ObjectStack MCP Server', + serverInfo: { + name: 'ObjectStack MCP', + version: '1.0.0', + capabilities: { + resources: true, + tools: true, + }, + }, + transport: { + type: 'stdio' as const, + command: 'node', + args: ['server.js'], + }, + }; + + const result = MCPServerConfigSchema.parse(config); + expect(result.autoStart).toBe(false); + expect(result.restartOnFailure).toBe(true); + expect(result.status).toBe('active'); + expect(result.version).toBe('1.0.0'); + }); + + it('should accept full server config', () => { + const config: MCPServerConfig = { + name: 'objectstack_mcp', + label: 'ObjectStack MCP Server', + description: 'MCP server exposing ObjectStack data and tools', + serverInfo: { + name: 'ObjectStack MCP', + version: '2.0.0', + description: 'Full-featured MCP server', + capabilities: { + resources: true, + resourceTemplates: true, + tools: true, + prompts: true, + sampling: true, + logging: true, + }, + vendor: 'ObjectStack AI', + }, + transport: { + type: 'http' as const, + url: 'https://mcp.objectstack.ai', + auth: { + type: 'bearer', + secretRef: 'system:mcp_api_key', + }, + timeout: 45000, + }, + resources: [ + { + uri: 'objectstack://metadata/objects', + name: 'Object Definitions', + description: 'List of all object definitions', + resourceType: 'json', + }, + ], + tools: [ + { + name: 'search_records', + description: 'Search for records', + parameters: [ + { + name: 'object', + type: 'string', + description: 'Object name', + required: true, + }, + ], + handler: 'data.search', + }, + ], + prompts: [ + { + name: 'analyze_data', + messages: [ + { + role: 'system', + content: 'You are a data analyst.', + }, + { + role: 'user', + content: 'Analyze this data: {{data}}', + }, + ], + }, + ], + autoStart: true, + restartOnFailure: true, + healthCheck: { + enabled: true, + interval: 30000, + timeout: 5000, + }, + permissions: { + allowedAgents: ['support_agent', 'data_analyst'], + requireAuth: true, + }, + rateLimit: { + enabled: true, + requestsPerMinute: 100, + requestsPerHour: 5000, + }, + tags: ['production', 'data'], + status: 'active', + version: '2.0.0', + }; + + expect(() => MCPServerConfigSchema.parse(config)).not.toThrow(); + }); +}); + +describe('MCPToolCallRequestSchema', () => { + it('should accept minimal tool call request', () => { + const request = { + toolName: 'search_records', + parameters: { + object: 'account', + query: 'name contains "Acme"', + }, + }; + + expect(() => MCPToolCallRequestSchema.parse(request)).not.toThrow(); + }); + + it('should accept tool call with context', () => { + const request = { + toolName: 'create_record', + parameters: { + object: 'task', + data: { title: 'New task' }, + }, + confirmationProvided: true, + context: { + userId: 'user123', + sessionId: 'session456', + agentName: 'support_agent', + metadata: { + source: 'chat', + }, + }, + }; + + expect(() => MCPToolCallRequestSchema.parse(request)).not.toThrow(); + }); +}); + +describe('MCPToolCallResponseSchema', () => { + it('should accept success response', () => { + const response = { + toolName: 'search_records', + status: 'success' as const, + result: [ + { id: '1', name: 'Record 1' }, + { id: '2', name: 'Record 2' }, + ], + executionTime: 125, + timestamp: '2024-01-01T00:00:00Z', + }; + + expect(() => MCPToolCallResponseSchema.parse(response)).not.toThrow(); + }); + + it('should accept error response', () => { + const response = { + toolName: 'create_record', + status: 'error' as const, + error: { + code: 'VALIDATION_ERROR', + message: 'Required field "title" is missing', + details: { field: 'title' }, + }, + executionTime: 50, + }; + + expect(() => MCPToolCallResponseSchema.parse(response)).not.toThrow(); + }); +}); + +describe('MCPResourceRequestSchema', () => { + it('should accept resource request', () => { + const request = { + uri: 'objectstack://objects/account/ABC123', + }; + + expect(() => MCPResourceRequestSchema.parse(request)).not.toThrow(); + }); + + it('should accept resource request with parameters', () => { + const request = { + uri: 'objectstack://objects/{objectName}/{recordId}', + parameters: { + objectName: 'account', + recordId: 'ABC123', + }, + }; + + expect(() => MCPResourceRequestSchema.parse(request)).not.toThrow(); + }); +}); + +describe('MCPPromptRequestSchema', () => { + it('should accept prompt request', () => { + const request = { + promptName: 'summarize_ticket', + arguments: { + ticket_content: 'User reports an issue with login', + }, + }; + + expect(() => MCPPromptRequestSchema.parse(request)).not.toThrow(); + }); +}); diff --git a/packages/spec/src/ai/mcp.zod.ts b/packages/spec/src/ai/mcp.zod.ts new file mode 100644 index 000000000..d57b9e0ec --- /dev/null +++ b/packages/spec/src/ai/mcp.zod.ts @@ -0,0 +1,483 @@ +import { z } from 'zod'; + +/** + * Model Context Protocol (MCP) + * + * Defines the protocol for connecting AI assistants to external tools, data sources, + * and resources. MCP enables AI models to access contextual information, invoke + * functions, and interact with external systems in a standardized way. + * + * Architecture Alignment: + * - Anthropic Model Context Protocol (MCP) + * - OpenAI Function Calling / Tools + * - LangChain Tool Interface + * - Microsoft Semantic Kernel Plugins + * + * Use Cases: + * - Connect AI agents to ObjectStack data (Objects, Views, Reports) + * - Expose business logic as callable tools (Workflows, Flows, Actions) + * - Provide dynamic context to AI models (User profile, Recent activity) + * - Enable AI to read and modify data through standardized interfaces + */ + +// ========================================== +// MCP Transport Configuration +// ========================================== + +/** + * MCP Transport Type + * Defines how the MCP server communicates + */ +export const MCPTransportTypeSchema = z.enum([ + 'stdio', // Standard input/output (for local processes) + 'http', // HTTP REST API + 'websocket', // WebSocket bidirectional communication + 'grpc', // gRPC for high-performance communication +]); + +/** + * MCP Transport Configuration + */ +export const MCPTransportConfigSchema = z.object({ + type: MCPTransportTypeSchema, + + /** HTTP/WebSocket Configuration */ + url: z.string().url().optional().describe('Server URL (for HTTP/WebSocket/gRPC)'), + headers: z.record(z.string(), z.string()).optional().describe('Custom headers for requests'), + + /** Authentication */ + auth: z.object({ + type: z.enum(['none', 'bearer', 'api_key', 'oauth2', 'custom']).default('none'), + token: z.string().optional().describe('Bearer token or API key'), + secretRef: z.string().optional().describe('Reference to stored secret'), + headerName: z.string().optional().describe('Custom auth header name'), + }).optional(), + + /** Connection Options */ + timeout: z.number().int().positive().optional().default(30000).describe('Request timeout in milliseconds'), + retryAttempts: z.number().int().min(0).max(5).optional().default(3), + retryDelay: z.number().int().positive().optional().default(1000).describe('Delay between retries in milliseconds'), + + /** STDIO Configuration */ + command: z.string().optional().describe('Command to execute (for stdio transport)'), + args: z.array(z.string()).optional().describe('Command arguments'), + env: z.record(z.string(), z.string()).optional().describe('Environment variables'), + workingDirectory: z.string().optional().describe('Working directory for the process'), +}); + +// ========================================== +// MCP Resource Protocol +// ========================================== + +/** + * MCP Resource Type + * Types of resources that can be exposed through MCP + */ +export const MCPResourceTypeSchema = z.enum([ + 'text', // Plain text or markdown content + 'json', // Structured JSON data + 'binary', // Binary data (files, images, etc.) + 'stream', // Streaming data +]); + +/** + * MCP Resource Schema + * Represents a piece of contextual information available to the AI + */ +export const MCPResourceSchema = z.object({ + /** Identity */ + uri: z.string().describe('Unique resource identifier (e.g., "objectstack://objects/account/ABC123")'), + name: z.string().describe('Human-readable resource name'), + description: z.string().optional().describe('Resource description for AI consumption'), + + /** Resource Type */ + mimeType: z.string().optional().describe('MIME type (e.g., "application/json", "text/plain")'), + resourceType: MCPResourceTypeSchema.default('json'), + + /** Content */ + content: z.unknown().optional().describe('Resource content (for static resources)'), + contentUrl: z.string().url().optional().describe('URL to fetch content dynamically'), + + /** Metadata */ + size: z.number().int().nonnegative().optional().describe('Resource size in bytes'), + lastModified: z.string().datetime().optional().describe('Last modification timestamp (ISO 8601)'), + tags: z.array(z.string()).optional().describe('Tags for resource categorization'), + + /** Access Control */ + permissions: z.object({ + read: z.boolean().default(true), + write: z.boolean().default(false), + delete: z.boolean().default(false), + }).optional(), + + /** Caching */ + cacheable: z.boolean().default(true).describe('Whether this resource can be cached'), + cacheMaxAge: z.number().int().nonnegative().optional().describe('Cache max age in seconds'), +}); + +/** + * MCP Resource Template + * Dynamic resource generation pattern + */ +export const MCPResourceTemplateSchema = z.object({ + uriPattern: z.string().describe('URI pattern with variables (e.g., "objectstack://objects/{objectName}/{recordId}")'), + name: z.string().describe('Template name'), + description: z.string().optional(), + + /** Parameters */ + parameters: z.array(z.object({ + name: z.string().describe('Parameter name'), + type: z.enum(['string', 'number', 'boolean']).default('string'), + required: z.boolean().default(true), + description: z.string().optional(), + pattern: z.string().optional().describe('Regex validation pattern'), + default: z.unknown().optional(), + })).describe('URI parameters'), + + /** Generation Logic */ + handler: z.string().optional().describe('Handler function name for dynamic generation'), + + mimeType: z.string().optional(), + resourceType: MCPResourceTypeSchema.default('json'), +}); + +// ========================================== +// MCP Tool Protocol +// ========================================== + +/** + * MCP Tool Parameter Schema + * Defines parameters for MCP tool functions + */ +export const MCPToolParameterSchema = z.object({ + name: z.string().describe('Parameter name'), + type: z.enum(['string', 'number', 'boolean', 'object', 'array']), + description: z.string().describe('Parameter description for AI consumption'), + required: z.boolean().default(false), + default: z.unknown().optional(), + + /** Validation */ + enum: z.array(z.unknown()).optional().describe('Allowed values'), + pattern: z.string().optional().describe('Regex validation pattern (for strings)'), + minimum: z.number().optional().describe('Minimum value (for numbers)'), + maximum: z.number().optional().describe('Maximum value (for numbers)'), + minLength: z.number().int().nonnegative().optional().describe('Minimum length (for strings/arrays)'), + maxLength: z.number().int().nonnegative().optional().describe('Maximum length (for strings/arrays)'), + + /** Nested Schema */ + properties: z.record(z.string(), z.lazy(() => MCPToolParameterSchema)).optional().describe('Properties for object types'), + items: z.lazy(() => MCPToolParameterSchema).optional().describe('Item schema for array types'), +}); + +/** + * MCP Tool Schema + * Represents a callable function or action available to the AI + */ +export const MCPToolSchema = z.object({ + /** Identity */ + name: z.string().regex(/^[a-z_][a-z0-9_]*$/).describe('Tool function name (snake_case)'), + description: z.string().describe('Tool description for AI consumption (be detailed and specific)'), + + /** Parameters */ + parameters: z.array(MCPToolParameterSchema).describe('Tool parameters'), + + /** Return Type */ + returns: z.object({ + type: z.enum(['string', 'number', 'boolean', 'object', 'array', 'void']), + description: z.string().optional(), + schema: MCPToolParameterSchema.optional().describe('Return value schema'), + }).optional(), + + /** Execution Configuration */ + handler: z.string().describe('Handler function or endpoint reference'), + async: z.boolean().default(true).describe('Whether the tool executes asynchronously'), + timeout: z.number().int().positive().optional().describe('Execution timeout in milliseconds'), + + /** Side Effects */ + sideEffects: z.enum(['none', 'read', 'write', 'delete']).default('read').describe('Tool side effects'), + requiresConfirmation: z.boolean().default(false).describe('Require user confirmation before execution'), + confirmationMessage: z.string().optional(), + + /** Examples */ + examples: z.array(z.object({ + description: z.string(), + parameters: z.record(z.string(), z.unknown()), + result: z.unknown().optional(), + })).optional().describe('Usage examples for AI learning'), + + /** Metadata */ + category: z.string().optional().describe('Tool category (e.g., "data", "workflow", "analytics")'), + tags: z.array(z.string()).optional(), + deprecated: z.boolean().default(false), + version: z.string().optional().default('1.0.0'), +}); + +// ========================================== +// MCP Prompt Protocol +// ========================================== + +/** + * MCP Prompt Argument + * Dynamic arguments for prompt templates + */ +export const MCPPromptArgumentSchema = z.object({ + name: z.string().describe('Argument name'), + description: z.string().optional(), + type: z.enum(['string', 'number', 'boolean']).default('string'), + required: z.boolean().default(false), + default: z.unknown().optional(), +}); + +/** + * MCP Prompt Message + * Individual message in a prompt template + */ +export const MCPPromptMessageSchema = z.object({ + role: z.enum(['system', 'user', 'assistant']).describe('Message role'), + content: z.string().describe('Message content (can include {{variable}} placeholders)'), +}); + +/** + * MCP Prompt Schema + * Predefined prompt templates available to the AI + */ +export const MCPPromptSchema = z.object({ + /** Identity */ + name: z.string().regex(/^[a-z_][a-z0-9_]*$/).describe('Prompt template name (snake_case)'), + description: z.string().optional().describe('Prompt description'), + + /** Template */ + messages: z.array(MCPPromptMessageSchema).describe('Prompt message sequence'), + + /** Arguments */ + arguments: z.array(MCPPromptArgumentSchema).optional().describe('Dynamic arguments for the prompt'), + + /** Metadata */ + category: z.string().optional(), + tags: z.array(z.string()).optional(), + version: z.string().optional().default('1.0.0'), +}); + +// ========================================== +// MCP Server Configuration +// ========================================== + +/** + * MCP Capability + * Features supported by the MCP server + */ +export const MCPCapabilitySchema = z.object({ + resources: z.boolean().default(false).describe('Supports resource listing and retrieval'), + resourceTemplates: z.boolean().default(false).describe('Supports dynamic resource templates'), + tools: z.boolean().default(false).describe('Supports tool/function calling'), + prompts: z.boolean().default(false).describe('Supports prompt templates'), + sampling: z.boolean().default(false).describe('Supports sampling from LLMs'), + logging: z.boolean().default(false).describe('Supports logging and debugging'), +}); + +/** + * MCP Server Info + * Server metadata and capabilities + */ +export const MCPServerInfoSchema = z.object({ + name: z.string().describe('Server name'), + version: z.string().describe('Server version (semver)'), + description: z.string().optional(), + capabilities: MCPCapabilitySchema, + + /** Protocol Version */ + protocolVersion: z.string().default('2024-11-05').describe('MCP protocol version'), + + /** Metadata */ + vendor: z.string().optional().describe('Server vendor/provider'), + homepage: z.string().url().optional().describe('Server homepage URL'), + documentation: z.string().url().optional().describe('Documentation URL'), +}); + +/** + * MCP Server Configuration + * Complete MCP server definition + */ +export const MCPServerConfigSchema = z.object({ + /** Identity */ + name: z.string().regex(/^[a-z_][a-z0-9_]*$/).describe('Server unique identifier (snake_case)'), + label: z.string().describe('Display name'), + description: z.string().optional(), + + /** Server Info */ + serverInfo: MCPServerInfoSchema, + + /** Transport */ + transport: MCPTransportConfigSchema, + + /** Resources */ + resources: z.array(MCPResourceSchema).optional().describe('Static resources'), + resourceTemplates: z.array(MCPResourceTemplateSchema).optional().describe('Dynamic resource templates'), + + /** Tools */ + tools: z.array(MCPToolSchema).optional().describe('Available tools'), + + /** Prompts */ + prompts: z.array(MCPPromptSchema).optional().describe('Prompt templates'), + + /** Lifecycle */ + autoStart: z.boolean().default(false).describe('Auto-start server on system boot'), + restartOnFailure: z.boolean().default(true).describe('Auto-restart on failure'), + healthCheck: z.object({ + enabled: z.boolean().default(true), + interval: z.number().int().positive().default(60000).describe('Health check interval in milliseconds'), + timeout: z.number().int().positive().default(5000).describe('Health check timeout in milliseconds'), + endpoint: z.string().optional().describe('Health check endpoint (for HTTP servers)'), + }).optional(), + + /** Access Control */ + permissions: z.object({ + allowedAgents: z.array(z.string()).optional().describe('Agent names allowed to use this server'), + allowedUsers: z.array(z.string()).optional().describe('User IDs allowed to use this server'), + requireAuth: z.boolean().default(true), + }).optional(), + + /** Rate Limiting */ + rateLimit: z.object({ + enabled: z.boolean().default(false), + requestsPerMinute: z.number().int().positive().optional(), + requestsPerHour: z.number().int().positive().optional(), + burstSize: z.number().int().positive().optional(), + }).optional(), + + /** Metadata */ + tags: z.array(z.string()).optional(), + status: z.enum(['active', 'inactive', 'maintenance', 'deprecated']).default('active'), + version: z.string().optional().default('1.0.0'), + createdAt: z.string().datetime().optional(), + updatedAt: z.string().datetime().optional(), +}); + +// ========================================== +// MCP Request/Response Schemas +// ========================================== + +/** + * MCP Resource Request + */ +export const MCPResourceRequestSchema = z.object({ + uri: z.string().describe('Resource URI to fetch'), + parameters: z.record(z.string(), z.unknown()).optional().describe('URI template parameters'), +}); + +/** + * MCP Resource Response + */ +export const MCPResourceResponseSchema = z.object({ + resource: MCPResourceSchema, + content: z.unknown().describe('Resource content'), +}); + +/** + * MCP Tool Call Request + */ +export const MCPToolCallRequestSchema = z.object({ + toolName: z.string().describe('Tool to invoke'), + parameters: z.record(z.string(), z.unknown()).describe('Tool parameters'), + + /** Execution Options */ + timeout: z.number().int().positive().optional(), + confirmationProvided: z.boolean().optional().describe('User confirmation for tools that require it'), + + /** Context */ + context: z.object({ + userId: z.string().optional(), + sessionId: z.string().optional(), + agentName: z.string().optional(), + metadata: z.record(z.string(), z.unknown()).optional(), + }).optional(), +}); + +/** + * MCP Tool Call Response + */ +export const MCPToolCallResponseSchema = z.object({ + toolName: z.string(), + status: z.enum(['success', 'error', 'timeout', 'cancelled']), + + /** Result */ + result: z.unknown().optional().describe('Tool execution result'), + + /** Error */ + error: z.object({ + code: z.string(), + message: z.string(), + details: z.unknown().optional(), + }).optional(), + + /** Metrics */ + executionTime: z.number().nonnegative().optional().describe('Execution time in milliseconds'), + timestamp: z.string().datetime().optional(), +}); + +/** + * MCP Prompt Request + */ +export const MCPPromptRequestSchema = z.object({ + promptName: z.string().describe('Prompt template to use'), + arguments: z.record(z.string(), z.unknown()).optional().describe('Prompt arguments'), +}); + +/** + * MCP Prompt Response + */ +export const MCPPromptResponseSchema = z.object({ + promptName: z.string(), + messages: z.array(MCPPromptMessageSchema).describe('Rendered prompt messages'), +}); + +// ========================================== +// MCP Client Configuration +// ========================================== + +/** + * MCP Client Configuration + * Configuration for AI clients connecting to MCP servers + */ +export const MCPClientConfigSchema = z.object({ + /** Server Connection */ + servers: z.array(MCPServerConfigSchema).describe('MCP servers to connect to'), + + /** Client Settings */ + defaultTimeout: z.number().int().positive().default(30000).describe('Default timeout for requests'), + enableCaching: z.boolean().default(true).describe('Enable client-side caching'), + cacheMaxAge: z.number().int().nonnegative().default(300).describe('Cache max age in seconds'), + + /** Retry Logic */ + retryAttempts: z.number().int().min(0).max(5).default(3), + retryDelay: z.number().int().positive().default(1000), + + /** Logging */ + enableLogging: z.boolean().default(true), + logLevel: z.enum(['debug', 'info', 'warn', 'error']).default('info'), +}); + +// ========================================== +// Type Exports +// ========================================== + +export type MCPTransportType = z.infer; +export type MCPTransportConfig = z.infer; +export type MCPResourceType = z.infer; +export type MCPResource = z.infer; +export type MCPResourceTemplate = z.infer; +export type MCPToolParameter = z.infer; +export type MCPTool = z.infer; +export type MCPPromptArgument = z.infer; +export type MCPPromptMessage = z.infer; +export type MCPPrompt = z.infer; +export type MCPCapability = z.infer; +export type MCPServerInfo = z.infer; +export type MCPServerConfig = z.infer; +export type MCPResourceRequest = z.infer; +export type MCPResourceResponse = z.infer; +export type MCPToolCallRequest = z.infer; +export type MCPToolCallResponse = z.infer; +export type MCPPromptRequest = z.infer; +export type MCPPromptResponse = z.infer; +export type MCPClientConfig = z.infer; From 384d8313dafd15176ef8663c9c12249dd88065aa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 8 Feb 2026 09:45:13 +0000 Subject: [PATCH 3/4] Add comprehensive MCP documentation and fix TypeScript build Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- packages/spec/docs/MCP_GUIDE.md | 454 ++++++++++++++++++ packages/spec/docs/MCP_GUIDE_CN.md | 742 +++++++++++++++++++++++++++++ packages/spec/src/ai/mcp.zod.ts | 23 +- 3 files changed, 1217 insertions(+), 2 deletions(-) create mode 100644 packages/spec/docs/MCP_GUIDE.md create mode 100644 packages/spec/docs/MCP_GUIDE_CN.md diff --git a/packages/spec/docs/MCP_GUIDE.md b/packages/spec/docs/MCP_GUIDE.md new file mode 100644 index 000000000..693c0157e --- /dev/null +++ b/packages/spec/docs/MCP_GUIDE.md @@ -0,0 +1,454 @@ +# MCP (Model Context Protocol) Integration Guide + +## Overview + +The Model Context Protocol (MCP) is a standardized protocol for connecting AI assistants to external tools, data sources, and resources. ObjectStack implements MCP to enable seamless integration between AI agents and business data, workflows, and services. + +## Core Concepts + +### 1. MCP Server + +An MCP server is a service endpoint that exposes capabilities to AI agents. Each server can provide: + +- **Resources**: Contextual information (data, documents, records) +- **Tools**: Callable functions and operations +- **Prompts**: Predefined prompt templates + +### 2. Transport + +Multiple transport protocols are supported: + +- **stdio**: Standard input/output (local processes) +- **http**: HTTP REST API +- **websocket**: Bidirectional WebSocket communication +- **grpc**: High-performance gRPC communication + +### 3. Capabilities + +MCP servers declare their supported features: + +- `resources`: Supports resource listing and retrieval +- `resourceTemplates`: Supports dynamic resource templates +- `tools`: Supports tool/function calling +- `prompts`: Supports prompt templates +- `sampling`: Supports LLM sampling +- `logging`: Supports logging and debugging + +## Quick Start + +### Define an MCP Server + +```typescript +import { MCPServerConfigSchema } from '@objectstack/spec/ai'; + +export const objectStackMCP = MCPServerConfigSchema.parse({ + // Server Identity + name: 'objectstack_mcp', + label: 'ObjectStack MCP Server', + description: 'Connects AI agents to ObjectStack data and workflows', + + // Server Info + serverInfo: { + name: 'ObjectStack MCP', + version: '1.0.0', + capabilities: { + resources: true, + resourceTemplates: true, + tools: true, + prompts: true, + }, + }, + + // Transport Configuration + transport: { + type: 'http', + url: 'https://api.objectstack.ai/mcp', + auth: { + type: 'bearer', + secretRef: 'system:mcp_api_key', + }, + }, + + // Expose business data as resources + resourceTemplates: [ + { + uriPattern: 'objectstack://objects/{objectName}', + name: 'Object Data', + description: 'Access object records', + parameters: [ + { + name: 'objectName', + type: 'string', + required: true, + description: 'Name of the object to access', + }, + ], + handler: 'resources.getObjectData', + }, + ], + + // Expose business operations as tools + tools: [ + { + name: 'create_record', + description: 'Create a new record in any object', + parameters: [ + { + name: 'object', + type: 'string', + description: 'Object name (e.g., "account", "contact")', + required: true, + }, + { + name: 'data', + type: 'object', + description: 'Record data as key-value pairs', + required: true, + }, + ], + handler: 'flows.create_record', + sideEffects: 'write', + requiresConfirmation: true, + }, + ], + + // Provide prompt templates + prompts: [ + { + name: 'analyze_customer_data', + description: 'Analyze customer data and generate insights', + messages: [ + { + role: 'system', + content: 'You are a data analyst specializing in customer insights.', + }, + { + role: 'user', + content: 'Analyze the following customer data and provide insights: {{customer_data}}', + }, + ], + arguments: [ + { + name: 'customer_data', + type: 'string', + required: true, + description: 'Customer data in JSON format', + }, + ], + }, + ], +}); +``` + +## Architecture + +``` +┌─────────────┐ ┌─────────────┐ ┌──────────────┐ +│ AI Agent │ ◄─MCP──►│ MCP Server │ ◄─────► │ ObjectStack │ +│ │ │ │ │ Data & Logic │ +└─────────────┘ └─────────────┘ └──────────────┘ + │ │ + │ ├─ Resources (Data) + │ ├─ Tools (Actions) + │ └─ Prompts (Templates) + │ + └─ Uses resources & tools to accomplish tasks +``` + +## Use Cases + +### 1. Expose ObjectStack Objects as MCP Resources + +Make your business data accessible to AI agents: + +```typescript +const resourceTemplates = [ + { + uriPattern: 'objectstack://objects/{objectName}/{recordId}', + name: 'Object Record Detail', + description: 'Get a single record from a specific object', + parameters: [ + { + name: 'objectName', + type: 'string', + required: true, + description: 'Object name (e.g., account, contact, task)', + }, + { + name: 'recordId', + type: 'string', + required: true, + description: 'Record ID', + }, + ], + handler: 'resources.getRecordDetail', + mimeType: 'application/json', + resourceType: 'json', + }, +]; +``` + +### 2. Expose Business Logic as MCP Tools + +Enable AI agents to execute business operations: + +```typescript +const tools = [ + { + name: 'search_records', + description: 'Search for records using natural language or filters', + parameters: [ + { + name: 'object', + type: 'string', + description: 'Object to search in', + required: true, + }, + { + name: 'query', + type: 'string', + description: 'Search query', + required: true, + }, + { + name: 'limit', + type: 'number', + description: 'Maximum number of results', + default: 10, + minimum: 1, + maximum: 100, + }, + ], + handler: 'data.search', + sideEffects: 'read', + }, + + { + name: 'trigger_workflow', + description: 'Trigger a business workflow', + parameters: [ + { + name: 'workflow_name', + type: 'string', + description: 'Workflow to trigger', + required: true, + }, + { + name: 'context_data', + type: 'object', + description: 'Context data for the workflow', + required: true, + }, + ], + handler: 'workflows.trigger', + sideEffects: 'write', + requiresConfirmation: true, + }, +]; +``` + +### 3. Provide Domain-Specific Prompt Templates + +Create specialized prompts for common business tasks: + +```typescript +const prompts = [ + { + name: 'analyze_sales_pipeline', + description: 'Analyze sales pipeline and provide recommendations', + messages: [ + { + role: 'system', + content: 'You are a sales analytics expert.', + }, + { + role: 'user', + content: `Analyze the following sales pipeline data: +Pipeline: {{pipeline_data}} +Time Period: {{time_period}} + +Provide: +1. Current pipeline health +2. Conversion rate analysis +3. Bottleneck identification +4. Recommended actions`, + }, + ], + arguments: [ + { + name: 'pipeline_data', + type: 'string', + required: true, + description: 'Sales pipeline data in JSON format', + }, + { + name: 'time_period', + type: 'string', + required: true, + description: 'Time period for analysis', + }, + ], + category: 'sales', + }, +]; +``` + +## Integration with AI Agents + +### Using MCP Tools in an Agent + +```typescript +import { AgentSchema } from '@objectstack/spec/ai'; + +export const salesAgent = AgentSchema.parse({ + name: 'sales_assistant', + label: 'Sales Assistant', + role: 'Sales Support Agent', + instructions: 'You help sales team with customer data and pipeline management.', + + model: { + provider: 'openai', + model: 'gpt-4-turbo', + temperature: 0.3, + }, + + // Reference MCP tools + tools: [ + { + type: 'action', + name: 'search_records', + description: 'Search for customer records', + }, + { + type: 'flow', + name: 'create_opportunity', + description: 'Create a new sales opportunity', + }, + ], + + knowledge: { + topics: ['sales_playbook', 'product_catalog'], + indexes: ['sales_knowledge_base'], + }, +}); +``` + +## Best Practices + +### 1. Tool Naming + +- Use `snake_case` naming +- Start with verbs (`create_`, `update_`, `search_`, `trigger_`) +- Make names descriptive and clear + +### 2. Parameter Design + +- Provide detailed descriptions to help AI understand usage +- Use appropriate types and validation rules +- Provide sensible defaults +- Use `enum` to constrain valid values + +### 3. Side Effects + +- `none`: No side effects (pure queries) +- `read`: Read-only operations +- `write`: Modifies data +- `delete`: Deletes data + +For operations with side effects, consider setting `requiresConfirmation: true` + +### 4. Security + +1. Use authentication (Bearer Token, API Key) +2. Implement access control (`allowedAgents`, `allowedUsers`) +3. Enable rate limiting (`rateLimit`) +4. Use HTTPS transport +5. Rotate keys regularly + +### 5. Performance + +- Use resource caching (`cacheable: true`) +- Set reasonable `cacheMaxAge` +- Implement rate limiting +- Monitor and log performance metrics + +## Advanced Configuration + +### Transport Examples + +#### HTTP Transport +```typescript +{ + type: 'http', + url: 'https://api.objectstack.ai/mcp', + auth: { + type: 'bearer', + secretRef: 'system:mcp_api_key', + }, + timeout: 30000, + retryAttempts: 3, +} +``` + +#### WebSocket Transport +```typescript +{ + type: 'websocket', + url: 'wss://api.objectstack.ai/mcp', + auth: { + type: 'bearer', + token: 'your-token', + }, + timeout: 60000, +} +``` + +#### stdio Transport +```typescript +{ + type: 'stdio', + command: 'node', + args: ['./mcp-server.js'], + env: { + NODE_ENV: 'production', + }, +} +``` + +### Health Checks + +```typescript +{ + healthCheck: { + enabled: true, + interval: 60000, + timeout: 5000, + endpoint: '/health', + }, + autoStart: true, + restartOnFailure: true, +} +``` + +### Access Control + +```typescript +{ + permissions: { + allowedAgents: ['support_agent', 'sales_agent'], + allowedUsers: ['admin@example.com'], + requireAuth: true, + }, + rateLimit: { + enabled: true, + requestsPerMinute: 100, + requestsPerHour: 5000, + }, +} +``` + +## Reference + +- [Model Context Protocol Official Docs](https://modelcontextprotocol.io) +- [ObjectStack Agent Configuration](./agent.zod.ts) +- [ObjectStack API Protocol](../api/protocol.zod.ts) diff --git a/packages/spec/docs/MCP_GUIDE_CN.md b/packages/spec/docs/MCP_GUIDE_CN.md new file mode 100644 index 000000000..792f52733 --- /dev/null +++ b/packages/spec/docs/MCP_GUIDE_CN.md @@ -0,0 +1,742 @@ +# MCP (Model Context Protocol) 集成指南 + +## 概述 + +Model Context Protocol (MCP) 是一个标准化协议,用于将 AI 助手连接到外部工具、数据源和资源。ObjectStack 通过 MCP 协议实现了 AI 代理与业务数据、工作流和服务的无缝集成。 + +## 核心概念 + +### 1. MCP 服务器 (MCP Server) + +MCP 服务器是向 AI 代理公开能力的服务端点。每个服务器可以提供: + +- **资源 (Resources)**: 上下文信息(数据、文档、记录) +- **工具 (Tools)**: 可调用的函数和操作 +- **提示模板 (Prompts)**: 预定义的提示词模板 + +### 2. 传输方式 (Transport) + +支持多种传输协议: + +- **stdio**: 标准输入/输出(本地进程) +- **http**: HTTP REST API +- **websocket**: WebSocket 双向通信 +- **grpc**: gRPC 高性能通信 + +### 3. 能力 (Capabilities) + +MCP 服务器可以声明支持的功能: + +- `resources`: 支持资源列表和检索 +- `resourceTemplates`: 支持动态资源模板 +- `tools`: 支持工具/函数调用 +- `prompts`: 支持提示模板 +- `sampling`: 支持 LLM 采样 +- `logging`: 支持日志记录 + +## 快速开始 + +### 定义 MCP 服务器 + +```typescript +import { MCPServerConfigSchema } from '@objectstack/spec/ai'; + +export const objectStackMCP = MCPServerConfigSchema.parse({ + // 服务器标识 + name: 'objectstack_mcp', + label: 'ObjectStack MCP 服务器', + description: '将 AI 代理连接到 ObjectStack 数据和工作流', + + // 服务器信息 + serverInfo: { + name: 'ObjectStack MCP', + version: '1.0.0', + capabilities: { + resources: true, + resourceTemplates: true, + tools: true, + prompts: true, + }, + }, + + // 传输配置 + transport: { + type: 'http', + url: 'https://api.objectstack.ai/mcp', + auth: { + type: 'bearer', + secretRef: 'system:mcp_api_key', + }, + }, + + // 将业务数据公开为资源 + resourceTemplates: [ + { + uriPattern: 'objectstack://objects/{objectName}', + name: '对象数据', + description: '访问对象记录', + parameters: [ + { + name: 'objectName', + type: 'string', + required: true, + description: '要访问的对象名称', + }, + ], + handler: 'resources.getObjectData', + }, + ], + + // 将业务操作公开为工具 + tools: [ + { + name: 'create_record', + description: '在任何对象中创建新记录', + parameters: [ + { + name: 'object', + type: 'string', + description: '对象名称(例如 "account", "contact")', + required: true, + }, + { + name: 'data', + type: 'object', + description: '记录数据,键值对格式', + required: true, + }, + ], + handler: 'flows.create_record', + sideEffects: 'write', + requiresConfirmation: true, + }, + ], + + // 提供提示模板 + prompts: [ + { + name: 'analyze_customer_data', + description: '分析客户数据并生成洞察', + messages: [ + { + role: 'system', + content: '你是一位专注于客户洞察的数据分析师。', + }, + { + role: 'user', + content: '分析以下客户数据并提供洞察:{{customer_data}}', + }, + ], + arguments: [ + { + name: 'customer_data', + type: 'string', + required: true, + description: 'JSON 格式的客户数据', + }, + ], + }, + ], +}); +``` + +## 详细使用场景 + +### 场景 1: 将 ObjectStack 对象公开为 MCP 资源 + +```typescript +// 定义动态资源模板 +const resourceTemplates = [ + { + uriPattern: 'objectstack://objects/{objectName}/{recordId}', + name: '对象记录详情', + description: '获取特定对象的单条记录', + parameters: [ + { + name: 'objectName', + type: 'string', + required: true, + description: '对象名称(如 account, contact, task)', + }, + { + name: 'recordId', + type: 'string', + required: true, + description: '记录 ID', + }, + ], + handler: 'resources.getRecordDetail', + mimeType: 'application/json', + resourceType: 'json', + }, + + // 列表视图资源 + { + uriPattern: 'objectstack://views/{viewName}', + name: '视图数据', + description: '获取特定视图的记录列表', + parameters: [ + { + name: 'viewName', + type: 'string', + required: true, + description: '视图名称', + }, + ], + handler: 'resources.getViewData', + }, + + // 报表资源 + { + uriPattern: 'objectstack://reports/{reportId}', + name: '报表数据', + description: '获取报表结果', + parameters: [ + { + name: 'reportId', + type: 'string', + required: true, + description: '报表 ID', + }, + ], + handler: 'resources.getReportData', + }, +]; +``` + +### 场景 2: 将业务流程公开为 MCP 工具 + +```typescript +const tools = [ + // 数据查询工具 + { + name: 'search_records', + description: '使用自然语言或过滤器搜索记录', + parameters: [ + { + name: 'object', + type: 'string', + description: '要搜索的对象', + required: true, + }, + { + name: 'query', + type: 'string', + description: '搜索查询', + required: true, + }, + { + name: 'limit', + type: 'number', + description: '最大结果数', + required: false, + default: 10, + minimum: 1, + maximum: 100, + }, + ], + handler: 'data.search', + sideEffects: 'read', + }, + + // 数据创建工具 + { + name: 'create_task', + description: '创建新任务', + parameters: [ + { + name: 'title', + type: 'string', + description: '任务标题', + required: true, + maxLength: 200, + }, + { + name: 'description', + type: 'string', + description: '任务描述', + required: false, + }, + { + name: 'priority', + type: 'string', + description: '优先级', + enum: ['low', 'medium', 'high', 'urgent'], + default: 'medium', + }, + { + name: 'assignee', + type: 'string', + description: '分配给(用户 ID)', + required: false, + }, + { + name: 'due_date', + type: 'string', + description: '截止日期(ISO 8601 格式)', + required: false, + }, + ], + handler: 'flows.create_task', + sideEffects: 'write', + requiresConfirmation: true, + confirmationMessage: '确认创建此任务?', + examples: [ + { + description: '创建高优先级任务', + parameters: { + title: '修复关键 Bug', + priority: 'high', + assignee: 'user_123', + }, + result: { + id: 'TASK-001', + status: 'created', + }, + }, + ], + }, + + // 工作流触发工具 + { + name: 'trigger_approval', + description: '触发审批流程', + parameters: [ + { + name: 'record_id', + type: 'string', + description: '需要审批的记录 ID', + required: true, + }, + { + name: 'approval_process', + type: 'string', + description: '审批流程名称', + required: true, + }, + { + name: 'approvers', + type: 'array', + description: '审批人 ID 列表', + items: { + name: 'approver_id', + type: 'string', + description: '审批人 ID', + required: true, + }, + }, + ], + handler: 'workflows.trigger_approval', + sideEffects: 'write', + }, + + // 数据分析工具 + { + name: 'generate_report', + description: '生成业务报表', + parameters: [ + { + name: 'report_type', + type: 'string', + description: '报表类型', + enum: ['sales', 'revenue', 'customer_analysis', 'inventory'], + required: true, + }, + { + name: 'time_period', + type: 'string', + description: '时间段', + enum: ['today', 'week', 'month', 'quarter', 'year'], + default: 'month', + }, + { + name: 'filters', + type: 'object', + description: '额外的过滤条件', + required: false, + }, + ], + handler: 'reports.generate', + sideEffects: 'read', + timeout: 60000, // 60 秒超时 + }, +]; +``` + +### 场景 3: 提供业务提示模板 + +```typescript +const prompts = [ + // 客户分析提示 + { + name: 'analyze_customer_behavior', + description: '分析客户行为模式', + messages: [ + { + role: 'system', + content: '你是一位客户行为分析专家,擅长从客户数据中发现模式和趋势。', + }, + { + role: 'user', + content: `分析以下客户的行为模式: +客户 ID: {{customer_id}} +购买历史: {{purchase_history}} +互动记录: {{interaction_history}} + +请提供: +1. 客户行为模式总结 +2. 购买偏好分析 +3. 流失风险评估 +4. 个性化推荐建议`, + }, + ], + arguments: [ + { + name: 'customer_id', + type: 'string', + required: true, + description: '客户唯一标识符', + }, + { + name: 'purchase_history', + type: 'string', + required: true, + description: 'JSON 格式的购买历史', + }, + { + name: 'interaction_history', + type: 'string', + required: true, + description: 'JSON 格式的互动记录', + }, + ], + category: 'analytics', + }, + + // 销售线索评分提示 + { + name: 'score_lead', + description: '评估销售线索质量', + messages: [ + { + role: 'system', + content: '你是一位销售线索评分专家,根据多个维度评估线索质量。', + }, + { + role: 'user', + content: `评估以下销售线索: +公司信息: {{company_info}} +联系人信息: {{contact_info}} +互动历史: {{engagement_data}} + +请提供: +1. 线索评分(0-100) +2. 评分依据 +3. 跟进建议 +4. 预计成交概率`, + }, + ], + arguments: [ + { + name: 'company_info', + type: 'string', + required: true, + }, + { + name: 'contact_info', + type: 'string', + required: true, + }, + { + name: 'engagement_data', + type: 'string', + required: true, + }, + ], + category: 'sales', + }, + + // 支持工单分类提示 + { + name: 'classify_support_ticket', + description: '自动分类支持工单', + messages: [ + { + role: 'system', + content: '你是一位客户支持专家,负责对工单进行分类和优先级评估。', + }, + { + role: 'user', + content: `分类以下支持工单: +标题: {{ticket_title}} +描述: {{ticket_description}} +客户: {{customer_tier}} + +请提供: +1. 工单类别(技术/账户/计费/功能请求) +2. 优先级(低/中/高/紧急) +3. 建议分配的团队 +4. 预估解决时间`, + }, + ], + arguments: [ + { + name: 'ticket_title', + type: 'string', + required: true, + }, + { + name: 'ticket_description', + type: 'string', + required: true, + }, + { + name: 'customer_tier', + type: 'string', + required: false, + default: 'standard', + }, + ], + category: 'support', + }, +]; +``` + +## 高级配置 + +### 传输配置示例 + +#### HTTP 传输 +```typescript +{ + type: 'http', + url: 'https://api.objectstack.ai/mcp', + auth: { + type: 'bearer', + secretRef: 'system:mcp_api_key', + }, + headers: { + 'X-API-Version': '1.0', + }, + timeout: 30000, + retryAttempts: 3, + retryDelay: 1000, +} +``` + +#### WebSocket 传输 +```typescript +{ + type: 'websocket', + url: 'wss://api.objectstack.ai/mcp', + auth: { + type: 'bearer', + token: 'your-token-here', + }, + timeout: 60000, +} +``` + +#### stdio 传输(本地进程) +```typescript +{ + type: 'stdio', + command: 'node', + args: ['./mcp-server.js'], + env: { + NODE_ENV: 'production', + DATABASE_URL: 'postgres://...', + }, + workingDirectory: '/opt/objectstack', +} +``` + +### 健康检查和监控 + +```typescript +{ + healthCheck: { + enabled: true, + interval: 60000, // 每 60 秒检查一次 + timeout: 5000, // 5 秒超时 + endpoint: '/health', // HTTP 健康检查端点 + }, + + // 自动重启配置 + autoStart: true, + restartOnFailure: true, +} +``` + +### 访问控制 + +```typescript +{ + permissions: { + allowedAgents: [ + 'support_agent', + 'sales_agent', + 'data_analyst_agent', + ], + allowedUsers: [ + 'admin@example.com', + 'user_123', + ], + requireAuth: true, + }, + + // 限流配置 + rateLimit: { + enabled: true, + requestsPerMinute: 100, + requestsPerHour: 5000, + burstSize: 20, + }, +} +``` + +## 与 AI 代理集成 + +### 在 Agent 中使用 MCP 服务器 + +```typescript +import { AgentSchema } from '@objectstack/spec/ai'; + +export const supportAgent = AgentSchema.parse({ + name: 'support_tier_1', + label: '一线支持代理', + role: '客户支持助理', + instructions: `你是一位专业的客户支持助理。 +你可以访问客户数据、工单系统和知识库。 +始终保持友好和专业的态度。`, + + model: { + provider: 'openai', + model: 'gpt-4-turbo', + temperature: 0.3, + }, + + // 引用 MCP 服务器的工具 + tools: [ + { + type: 'action', + name: 'search_records', + description: '搜索客户记录和工单', + }, + { + type: 'action', + name: 'create_task', + description: '创建跟进任务', + }, + { + type: 'flow', + name: 'trigger_approval', + description: '触发退款审批流程', + }, + ], + + knowledge: { + topics: ['support_docs', 'product_manual', 'faq'], + indexes: ['support_knowledge_base'], + }, +}); +``` + +## 最佳实践 + +### 1. 工具命名规范 + +- 使用 `snake_case` 命名 +- 使用动词开头(`create_`, `update_`, `search_`, `trigger_`) +- 名称应清晰描述功能 + +### 2. 参数设计 + +- 提供详细的描述,帮助 AI 理解如何使用 +- 使用合适的类型和验证规则 +- 提供合理的默认值 +- 使用 `enum` 限制可选值 + +### 3. 副作用声明 + +- `none`: 无副作用(纯查询) +- `read`: 只读操作 +- `write`: 修改数据 +- `delete`: 删除数据 + +对于有副作用的操作,考虑设置 `requiresConfirmation: true` + +### 4. 错误处理 + +- 提供清晰的错误消息 +- 使用适当的超时配置 +- 实现重试机制 + +### 5. 性能优化 + +- 使用资源缓存(`cacheable: true`) +- 设置合理的 `cacheMaxAge` +- 实施限流保护 +- 监控和记录性能指标 + +## 调试和测试 + +### 启用日志记录 + +```typescript +{ + serverInfo: { + capabilities: { + logging: true, + }, + }, +} +``` + +### 工具调用示例 + +```typescript +import { MCPToolCallRequestSchema } from '@objectstack/spec/ai'; + +const request = MCPToolCallRequestSchema.parse({ + toolName: 'create_task', + parameters: { + title: '跟进客户 ABC Corp', + priority: 'high', + assignee: 'user_123', + }, + context: { + userId: 'agent_001', + sessionId: 'session_456', + agentName: 'support_agent', + }, +}); +``` + +## 常见问题 + +### Q: MCP 与 Agent Actions 的区别? + +- **Agent Actions**: ObjectStack 内部的 UI 操作(导航、表单填写) +- **MCP Tools**: 通用的函数调用协议,可以是数据操作、外部 API 调用等 + +### Q: 如何选择传输方式? + +- **stdio**: 本地开发和测试 +- **http**: 生产环境、跨网络通信 +- **websocket**: 需要实时双向通信 +- **grpc**: 高性能场景 + +### Q: 如何保护 MCP 服务器? + +1. 使用身份验证(Bearer Token、API Key) +2. 实施访问控制(`allowedAgents`, `allowedUsers`) +3. 启用限流(`rateLimit`) +4. 使用 HTTPS 传输 +5. 定期轮换密钥 + +## 参考资料 + +- [Model Context Protocol 官方文档](https://modelcontextprotocol.io) +- [ObjectStack Agent 配置](./agent.zod.ts) +- [ObjectStack API 协议](../api/protocol.zod.ts) diff --git a/packages/spec/src/ai/mcp.zod.ts b/packages/spec/src/ai/mcp.zod.ts index d57b9e0ec..4036de354 100644 --- a/packages/spec/src/ai/mcp.zod.ts +++ b/packages/spec/src/ai/mcp.zod.ts @@ -149,7 +149,7 @@ export const MCPResourceTemplateSchema = z.object({ * MCP Tool Parameter Schema * Defines parameters for MCP tool functions */ -export const MCPToolParameterSchema = z.object({ +export const MCPToolParameterSchema: z.ZodType = z.object({ name: z.string().describe('Parameter name'), type: z.enum(['string', 'number', 'boolean', 'object', 'array']), description: z.string().describe('Parameter description for AI consumption'), @@ -169,6 +169,25 @@ export const MCPToolParameterSchema = z.object({ items: z.lazy(() => MCPToolParameterSchema).optional().describe('Item schema for array types'), }); +/** + * MCP Tool Parameter Type (inferred before schema to avoid circular reference) + */ +export type MCPToolParameter = { + name: string; + type: 'string' | 'number' | 'boolean' | 'object' | 'array'; + description: string; + required?: boolean; + default?: unknown; + enum?: unknown[]; + pattern?: string; + minimum?: number; + maximum?: number; + minLength?: number; + maxLength?: number; + properties?: Record; + items?: MCPToolParameter; +}; + /** * MCP Tool Schema * Represents a callable function or action available to the AI @@ -466,7 +485,7 @@ export type MCPTransportConfig = z.infer; export type MCPResourceType = z.infer; export type MCPResource = z.infer; export type MCPResourceTemplate = z.infer; -export type MCPToolParameter = z.infer; +// MCPToolParameter type is exported above with the schema export type MCPTool = z.infer; export type MCPPromptArgument = z.infer; export type MCPPromptMessage = z.infer; From 122a829da8288a7ea923dfbf20c8fe5fb2129d06 Mon Sep 17 00:00:00 2001 From: Jack Zhuang <50353452+hotlong@users.noreply.github.com> Date: Sun, 8 Feb 2026 18:16:19 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E5=88=A0=E9=99=A4=20MCP=5FGUIDE=5FCN.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/spec/docs/MCP_GUIDE_CN.md | 742 ----------------------------- 1 file changed, 742 deletions(-) delete mode 100644 packages/spec/docs/MCP_GUIDE_CN.md diff --git a/packages/spec/docs/MCP_GUIDE_CN.md b/packages/spec/docs/MCP_GUIDE_CN.md deleted file mode 100644 index 792f52733..000000000 --- a/packages/spec/docs/MCP_GUIDE_CN.md +++ /dev/null @@ -1,742 +0,0 @@ -# MCP (Model Context Protocol) 集成指南 - -## 概述 - -Model Context Protocol (MCP) 是一个标准化协议,用于将 AI 助手连接到外部工具、数据源和资源。ObjectStack 通过 MCP 协议实现了 AI 代理与业务数据、工作流和服务的无缝集成。 - -## 核心概念 - -### 1. MCP 服务器 (MCP Server) - -MCP 服务器是向 AI 代理公开能力的服务端点。每个服务器可以提供: - -- **资源 (Resources)**: 上下文信息(数据、文档、记录) -- **工具 (Tools)**: 可调用的函数和操作 -- **提示模板 (Prompts)**: 预定义的提示词模板 - -### 2. 传输方式 (Transport) - -支持多种传输协议: - -- **stdio**: 标准输入/输出(本地进程) -- **http**: HTTP REST API -- **websocket**: WebSocket 双向通信 -- **grpc**: gRPC 高性能通信 - -### 3. 能力 (Capabilities) - -MCP 服务器可以声明支持的功能: - -- `resources`: 支持资源列表和检索 -- `resourceTemplates`: 支持动态资源模板 -- `tools`: 支持工具/函数调用 -- `prompts`: 支持提示模板 -- `sampling`: 支持 LLM 采样 -- `logging`: 支持日志记录 - -## 快速开始 - -### 定义 MCP 服务器 - -```typescript -import { MCPServerConfigSchema } from '@objectstack/spec/ai'; - -export const objectStackMCP = MCPServerConfigSchema.parse({ - // 服务器标识 - name: 'objectstack_mcp', - label: 'ObjectStack MCP 服务器', - description: '将 AI 代理连接到 ObjectStack 数据和工作流', - - // 服务器信息 - serverInfo: { - name: 'ObjectStack MCP', - version: '1.0.0', - capabilities: { - resources: true, - resourceTemplates: true, - tools: true, - prompts: true, - }, - }, - - // 传输配置 - transport: { - type: 'http', - url: 'https://api.objectstack.ai/mcp', - auth: { - type: 'bearer', - secretRef: 'system:mcp_api_key', - }, - }, - - // 将业务数据公开为资源 - resourceTemplates: [ - { - uriPattern: 'objectstack://objects/{objectName}', - name: '对象数据', - description: '访问对象记录', - parameters: [ - { - name: 'objectName', - type: 'string', - required: true, - description: '要访问的对象名称', - }, - ], - handler: 'resources.getObjectData', - }, - ], - - // 将业务操作公开为工具 - tools: [ - { - name: 'create_record', - description: '在任何对象中创建新记录', - parameters: [ - { - name: 'object', - type: 'string', - description: '对象名称(例如 "account", "contact")', - required: true, - }, - { - name: 'data', - type: 'object', - description: '记录数据,键值对格式', - required: true, - }, - ], - handler: 'flows.create_record', - sideEffects: 'write', - requiresConfirmation: true, - }, - ], - - // 提供提示模板 - prompts: [ - { - name: 'analyze_customer_data', - description: '分析客户数据并生成洞察', - messages: [ - { - role: 'system', - content: '你是一位专注于客户洞察的数据分析师。', - }, - { - role: 'user', - content: '分析以下客户数据并提供洞察:{{customer_data}}', - }, - ], - arguments: [ - { - name: 'customer_data', - type: 'string', - required: true, - description: 'JSON 格式的客户数据', - }, - ], - }, - ], -}); -``` - -## 详细使用场景 - -### 场景 1: 将 ObjectStack 对象公开为 MCP 资源 - -```typescript -// 定义动态资源模板 -const resourceTemplates = [ - { - uriPattern: 'objectstack://objects/{objectName}/{recordId}', - name: '对象记录详情', - description: '获取特定对象的单条记录', - parameters: [ - { - name: 'objectName', - type: 'string', - required: true, - description: '对象名称(如 account, contact, task)', - }, - { - name: 'recordId', - type: 'string', - required: true, - description: '记录 ID', - }, - ], - handler: 'resources.getRecordDetail', - mimeType: 'application/json', - resourceType: 'json', - }, - - // 列表视图资源 - { - uriPattern: 'objectstack://views/{viewName}', - name: '视图数据', - description: '获取特定视图的记录列表', - parameters: [ - { - name: 'viewName', - type: 'string', - required: true, - description: '视图名称', - }, - ], - handler: 'resources.getViewData', - }, - - // 报表资源 - { - uriPattern: 'objectstack://reports/{reportId}', - name: '报表数据', - description: '获取报表结果', - parameters: [ - { - name: 'reportId', - type: 'string', - required: true, - description: '报表 ID', - }, - ], - handler: 'resources.getReportData', - }, -]; -``` - -### 场景 2: 将业务流程公开为 MCP 工具 - -```typescript -const tools = [ - // 数据查询工具 - { - name: 'search_records', - description: '使用自然语言或过滤器搜索记录', - parameters: [ - { - name: 'object', - type: 'string', - description: '要搜索的对象', - required: true, - }, - { - name: 'query', - type: 'string', - description: '搜索查询', - required: true, - }, - { - name: 'limit', - type: 'number', - description: '最大结果数', - required: false, - default: 10, - minimum: 1, - maximum: 100, - }, - ], - handler: 'data.search', - sideEffects: 'read', - }, - - // 数据创建工具 - { - name: 'create_task', - description: '创建新任务', - parameters: [ - { - name: 'title', - type: 'string', - description: '任务标题', - required: true, - maxLength: 200, - }, - { - name: 'description', - type: 'string', - description: '任务描述', - required: false, - }, - { - name: 'priority', - type: 'string', - description: '优先级', - enum: ['low', 'medium', 'high', 'urgent'], - default: 'medium', - }, - { - name: 'assignee', - type: 'string', - description: '分配给(用户 ID)', - required: false, - }, - { - name: 'due_date', - type: 'string', - description: '截止日期(ISO 8601 格式)', - required: false, - }, - ], - handler: 'flows.create_task', - sideEffects: 'write', - requiresConfirmation: true, - confirmationMessage: '确认创建此任务?', - examples: [ - { - description: '创建高优先级任务', - parameters: { - title: '修复关键 Bug', - priority: 'high', - assignee: 'user_123', - }, - result: { - id: 'TASK-001', - status: 'created', - }, - }, - ], - }, - - // 工作流触发工具 - { - name: 'trigger_approval', - description: '触发审批流程', - parameters: [ - { - name: 'record_id', - type: 'string', - description: '需要审批的记录 ID', - required: true, - }, - { - name: 'approval_process', - type: 'string', - description: '审批流程名称', - required: true, - }, - { - name: 'approvers', - type: 'array', - description: '审批人 ID 列表', - items: { - name: 'approver_id', - type: 'string', - description: '审批人 ID', - required: true, - }, - }, - ], - handler: 'workflows.trigger_approval', - sideEffects: 'write', - }, - - // 数据分析工具 - { - name: 'generate_report', - description: '生成业务报表', - parameters: [ - { - name: 'report_type', - type: 'string', - description: '报表类型', - enum: ['sales', 'revenue', 'customer_analysis', 'inventory'], - required: true, - }, - { - name: 'time_period', - type: 'string', - description: '时间段', - enum: ['today', 'week', 'month', 'quarter', 'year'], - default: 'month', - }, - { - name: 'filters', - type: 'object', - description: '额外的过滤条件', - required: false, - }, - ], - handler: 'reports.generate', - sideEffects: 'read', - timeout: 60000, // 60 秒超时 - }, -]; -``` - -### 场景 3: 提供业务提示模板 - -```typescript -const prompts = [ - // 客户分析提示 - { - name: 'analyze_customer_behavior', - description: '分析客户行为模式', - messages: [ - { - role: 'system', - content: '你是一位客户行为分析专家,擅长从客户数据中发现模式和趋势。', - }, - { - role: 'user', - content: `分析以下客户的行为模式: -客户 ID: {{customer_id}} -购买历史: {{purchase_history}} -互动记录: {{interaction_history}} - -请提供: -1. 客户行为模式总结 -2. 购买偏好分析 -3. 流失风险评估 -4. 个性化推荐建议`, - }, - ], - arguments: [ - { - name: 'customer_id', - type: 'string', - required: true, - description: '客户唯一标识符', - }, - { - name: 'purchase_history', - type: 'string', - required: true, - description: 'JSON 格式的购买历史', - }, - { - name: 'interaction_history', - type: 'string', - required: true, - description: 'JSON 格式的互动记录', - }, - ], - category: 'analytics', - }, - - // 销售线索评分提示 - { - name: 'score_lead', - description: '评估销售线索质量', - messages: [ - { - role: 'system', - content: '你是一位销售线索评分专家,根据多个维度评估线索质量。', - }, - { - role: 'user', - content: `评估以下销售线索: -公司信息: {{company_info}} -联系人信息: {{contact_info}} -互动历史: {{engagement_data}} - -请提供: -1. 线索评分(0-100) -2. 评分依据 -3. 跟进建议 -4. 预计成交概率`, - }, - ], - arguments: [ - { - name: 'company_info', - type: 'string', - required: true, - }, - { - name: 'contact_info', - type: 'string', - required: true, - }, - { - name: 'engagement_data', - type: 'string', - required: true, - }, - ], - category: 'sales', - }, - - // 支持工单分类提示 - { - name: 'classify_support_ticket', - description: '自动分类支持工单', - messages: [ - { - role: 'system', - content: '你是一位客户支持专家,负责对工单进行分类和优先级评估。', - }, - { - role: 'user', - content: `分类以下支持工单: -标题: {{ticket_title}} -描述: {{ticket_description}} -客户: {{customer_tier}} - -请提供: -1. 工单类别(技术/账户/计费/功能请求) -2. 优先级(低/中/高/紧急) -3. 建议分配的团队 -4. 预估解决时间`, - }, - ], - arguments: [ - { - name: 'ticket_title', - type: 'string', - required: true, - }, - { - name: 'ticket_description', - type: 'string', - required: true, - }, - { - name: 'customer_tier', - type: 'string', - required: false, - default: 'standard', - }, - ], - category: 'support', - }, -]; -``` - -## 高级配置 - -### 传输配置示例 - -#### HTTP 传输 -```typescript -{ - type: 'http', - url: 'https://api.objectstack.ai/mcp', - auth: { - type: 'bearer', - secretRef: 'system:mcp_api_key', - }, - headers: { - 'X-API-Version': '1.0', - }, - timeout: 30000, - retryAttempts: 3, - retryDelay: 1000, -} -``` - -#### WebSocket 传输 -```typescript -{ - type: 'websocket', - url: 'wss://api.objectstack.ai/mcp', - auth: { - type: 'bearer', - token: 'your-token-here', - }, - timeout: 60000, -} -``` - -#### stdio 传输(本地进程) -```typescript -{ - type: 'stdio', - command: 'node', - args: ['./mcp-server.js'], - env: { - NODE_ENV: 'production', - DATABASE_URL: 'postgres://...', - }, - workingDirectory: '/opt/objectstack', -} -``` - -### 健康检查和监控 - -```typescript -{ - healthCheck: { - enabled: true, - interval: 60000, // 每 60 秒检查一次 - timeout: 5000, // 5 秒超时 - endpoint: '/health', // HTTP 健康检查端点 - }, - - // 自动重启配置 - autoStart: true, - restartOnFailure: true, -} -``` - -### 访问控制 - -```typescript -{ - permissions: { - allowedAgents: [ - 'support_agent', - 'sales_agent', - 'data_analyst_agent', - ], - allowedUsers: [ - 'admin@example.com', - 'user_123', - ], - requireAuth: true, - }, - - // 限流配置 - rateLimit: { - enabled: true, - requestsPerMinute: 100, - requestsPerHour: 5000, - burstSize: 20, - }, -} -``` - -## 与 AI 代理集成 - -### 在 Agent 中使用 MCP 服务器 - -```typescript -import { AgentSchema } from '@objectstack/spec/ai'; - -export const supportAgent = AgentSchema.parse({ - name: 'support_tier_1', - label: '一线支持代理', - role: '客户支持助理', - instructions: `你是一位专业的客户支持助理。 -你可以访问客户数据、工单系统和知识库。 -始终保持友好和专业的态度。`, - - model: { - provider: 'openai', - model: 'gpt-4-turbo', - temperature: 0.3, - }, - - // 引用 MCP 服务器的工具 - tools: [ - { - type: 'action', - name: 'search_records', - description: '搜索客户记录和工单', - }, - { - type: 'action', - name: 'create_task', - description: '创建跟进任务', - }, - { - type: 'flow', - name: 'trigger_approval', - description: '触发退款审批流程', - }, - ], - - knowledge: { - topics: ['support_docs', 'product_manual', 'faq'], - indexes: ['support_knowledge_base'], - }, -}); -``` - -## 最佳实践 - -### 1. 工具命名规范 - -- 使用 `snake_case` 命名 -- 使用动词开头(`create_`, `update_`, `search_`, `trigger_`) -- 名称应清晰描述功能 - -### 2. 参数设计 - -- 提供详细的描述,帮助 AI 理解如何使用 -- 使用合适的类型和验证规则 -- 提供合理的默认值 -- 使用 `enum` 限制可选值 - -### 3. 副作用声明 - -- `none`: 无副作用(纯查询) -- `read`: 只读操作 -- `write`: 修改数据 -- `delete`: 删除数据 - -对于有副作用的操作,考虑设置 `requiresConfirmation: true` - -### 4. 错误处理 - -- 提供清晰的错误消息 -- 使用适当的超时配置 -- 实现重试机制 - -### 5. 性能优化 - -- 使用资源缓存(`cacheable: true`) -- 设置合理的 `cacheMaxAge` -- 实施限流保护 -- 监控和记录性能指标 - -## 调试和测试 - -### 启用日志记录 - -```typescript -{ - serverInfo: { - capabilities: { - logging: true, - }, - }, -} -``` - -### 工具调用示例 - -```typescript -import { MCPToolCallRequestSchema } from '@objectstack/spec/ai'; - -const request = MCPToolCallRequestSchema.parse({ - toolName: 'create_task', - parameters: { - title: '跟进客户 ABC Corp', - priority: 'high', - assignee: 'user_123', - }, - context: { - userId: 'agent_001', - sessionId: 'session_456', - agentName: 'support_agent', - }, -}); -``` - -## 常见问题 - -### Q: MCP 与 Agent Actions 的区别? - -- **Agent Actions**: ObjectStack 内部的 UI 操作(导航、表单填写) -- **MCP Tools**: 通用的函数调用协议,可以是数据操作、外部 API 调用等 - -### Q: 如何选择传输方式? - -- **stdio**: 本地开发和测试 -- **http**: 生产环境、跨网络通信 -- **websocket**: 需要实时双向通信 -- **grpc**: 高性能场景 - -### Q: 如何保护 MCP 服务器? - -1. 使用身份验证(Bearer Token、API Key) -2. 实施访问控制(`allowedAgents`, `allowedUsers`) -3. 启用限流(`rateLimit`) -4. 使用 HTTPS 传输 -5. 定期轮换密钥 - -## 参考资料 - -- [Model Context Protocol 官方文档](https://modelcontextprotocol.io) -- [ObjectStack Agent 配置](./agent.zod.ts) -- [ObjectStack API 协议](../api/protocol.zod.ts)