Publish MCP Services
Publish REST endpoints and workflows as discoverable MCP (Model Context Protocol) services in ValkyrAI.
Quick Start
Publish a REST Controller
curl -X POST http://localhost:8080/v1/mcp/publish-rest-endpoint \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <JWT_TOKEN>" \
-d '{
"controllerPath": "com.valkyrlabs.api.UserController",
"toolSlug": "user-service",
"displayName": "User Management Service",
"category": "UTILITY",
"apiBaseUrl": "http://localhost:8080",
"summary": "Manage user accounts and profiles",
"tags": ["users", "accounts"],
"authorName": "ValkyrAI Team",
"autoApprove": true
}'
Response:
{
"serviceId": "550e8400-e29b-41d4-a716-446655440000",
"slug": "user-service",
"status": "PUBLISHED",
"manifestUrl": "http://localhost:8080/v1/mcp/services/user-service/manifest.yaml",
"message": "Successfully published 12 endpoint(s) as MCP tools"
}
Publish a Workflow
curl -X POST http://localhost:8080/v1/mcp/publish-workflow \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <JWT_TOKEN>" \
-d '{
"workflowId": "workflow-123",
"toolSlug": "email-campaign",
"displayName": "Email Campaign Launcher",
"category": "AUTOMATION",
"description": "Send targeted email campaigns to user segments",
"tags": ["email", "marketing", "automation"]
}'
API Reference
Endpoints
| Method | Endpoint | Description |
|---|---|---|
POST | /v1/mcp/publish-rest-endpoint | Publish Spring controller |
POST | /v1/mcp/publish-workflow | Publish workflow |
GET | /v1/mcp/services | List services (paginated) |
GET | /v1/mcp/services/{slug} | Get service details |
PUT | /v1/mcp/services/{slug} | Update metadata |
DELETE | /v1/mcp/services/{slug} | Unpublish service |
GET | /v1/mcp/services/{slug}/manifest.yaml | Download manifest |
List Services
curl http://localhost:8080/v1/mcp/services?page=0&size=20 \
-H "Authorization: Bearer <JWT_TOKEN>"
Get Service Details
curl http://localhost:8080/v1/mcp/services/user-service \
-H "Authorization: Bearer <JWT_TOKEN>"
Update Service
curl -X PUT http://localhost:8080/v1/mcp/services/user-service \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <JWT_TOKEN>" \
-d '{
"displayName": "User Management Service (v2)",
"tags": ["users", "accounts", "updated"]
}'
Unpublish Service
curl -X DELETE http://localhost:8080/v1/mcp/services/user-service \
-H "Authorization: Bearer <JWT_TOKEN>"
HTTP Status Codes
| Code | Meaning | Example |
|---|---|---|
200 | Success | Service retrieved/updated |
201 | Created | Service published successfully |
204 | No Content | Service deleted successfully |
400 | Bad Request | Invalid controller path, no endpoints found |
401 | Unauthorized | Missing JWT token |
403 | Forbidden | Insufficient permissions (need ADMIN/DEVELOPER role) |
404 | Not Found | Service slug doesn't exist |
500 | Server Error | Unexpected error - check logs |
Security
Required Roles
| Operation | Role Required |
|---|---|
| List services | Any |
| Get service details | Any |
| Download manifest | Any |
| Invoke tool | Any |
| Publish endpoint | ADMIN, DEVELOPER |
| Publish workflow | ADMIN, DEVELOPER |
| Update service | ADMIN, DEVELOPER |
| Delete service | ADMIN, DEVELOPER |
Authentication
Include JWT bearer token in Authorization header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Data Models
PublishRestEndpointRequest
{
"controllerPath": "com.valkyrlabs.api.UserController",
"toolSlug": "user-service",
"displayName": "User Service",
"category": "UTILITY",
"apiBaseUrl": "http://localhost:8080",
"summary": "User management endpoints",
"description": "Full user account lifecycle management",
"documentationUrl": "https://docs.example.com/users",
"authorName": "ValkyrAI Team",
"repositoryUrl": "https://github.com/valkyrlabs/valkyr",
"icon": "https://example.com/icons/users.png",
"tags": ["users", "accounts", "api"],
"autoApprove": true
}
PublishWorkflowRequest
{
"workflowId": "workflow-123",
"toolSlug": "email-campaign",
"displayName": "Email Campaign",
"description": "Send targeted email campaigns",
"category": "AUTOMATION",
"tags": ["email", "marketing"],
"inputMapping": {
"recipientList": "campaign.recipients",
"emailTemplate": "campaign.template"
},
"outputMapping": {
"sentCount": "result.emailsSent",
"failureCount": "result.emailsFailed"
}
}
McpServiceRegistry (Response)
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"slug": "user-service",
"displayName": "User Service",
"description": "User management endpoints",
"category": "UTILITY",
"author": "ValkyrAI Team",
"apiBaseUrl": "http://localhost:8080",
"manifestUrl": "http://localhost:8080/v1/mcp/services/user-service/manifest.yaml",
"version": "1.0.0",
"isPublished": true,
"installCount": 42,
"tags": ["users", "accounts"],
"publishedDate": "2024-01-15T10:30:00Z",
"updatedDate": "2024-01-15T10:30:00Z"
}
Publication Flow
REST Endpoint Publishing
Request: Publish Controller
↓
1. Load controller by class name
↓
2. Scanner detects @RequestMapping methods
↓
3. Extract HTTP metadata
├─ HTTP method (GET, POST, etc)
├─ URL path & parameters
├─ Request/response schemas
└─ Endpoint documentation
↓
4. Create MCP server entry
↓
5. For each endpoint → Create MCP tool
↓
Response: 201 Created
Workflow Publishing
Request: Publish Workflow
↓
1. Create MCP server instance
↓
2. Map workflow parameters to tool inputs
↓
3. Map workflow outputs to tool outputs
↓
Response: 201 Created
Categories
Valid category values:
APPLICATIONAUTOMATIONDATA_PROCESSINGINTEGRATIONMESSAGINGUTILITYWORKFLOWAI_MLANALYTICSSECURITYPERFORMANCEMONITORING
Unknown categories default to APPLICATION.
Use Cases
Use Case 1: Expose Internal APIs
Make your internal REST API available as MCP services for external consumption:
curl -X POST http://localhost:8080/v1/mcp/publish-rest-endpoint \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-d '{
"controllerPath": "com.company.api.PaymentController",
"toolSlug": "payment-processor",
"displayName": "Payment Processor",
"category": "INTEGRATION",
"apiBaseUrl": "https://api.company.com"
}'
Use Case 2: Publish Automated Workflows
Make workflow executions available as callable MCP tools:
curl -X POST http://localhost:8080/v1/mcp/publish-workflow \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $DEV_TOKEN" \
-d '{
"workflowId": "daily-report-generator",
"toolSlug": "generate-reports",
"displayName": "Generate Daily Reports",
"category": "AUTOMATION"
}'
Use Case 3: Browse Available Services
List all published services:
curl http://localhost:8080/v1/mcp/services?page=0&size=50 \
-H "Authorization: Bearer $TOKEN" | jq '.[] | {slug, displayName, category, tags}'
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
Controller class not found | Invalid controllerPath FQCN | Check class name, ensure it's on classpath |
No publishable endpoints found | Controller has no @RequestMapping methods | Add @GetMapping, @PostMapping, etc. |
401 Unauthorized | Missing JWT token | Include Authorization: Bearer <token> header |
403 Forbidden | Insufficient permissions | User needs ADMIN or DEVELOPER role |
404 Not Found | Service slug doesn't exist | Check slug spelling, list services to verify |
500 Internal Server Error | Unexpected exception | Check application logs for details |
Testing
Test 1: Publish Controller
# Publish the MCP publishing controller as MCP services
curl -X POST http://localhost:8080/v1/mcp/publish-rest-endpoint \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"controllerPath": "com.valkyrlabs.valkyrai.controller.McpPublishingController",
"toolSlug": "mcp-publisher",
"displayName": "MCP Publishing API",
"category": "UTILITY",
"apiBaseUrl": "http://localhost:8080"
}'
Test 2: List and Filter
# Get first 10 services
curl "http://localhost:8080/v1/mcp/services?page=0&size=10" \
-H "Authorization: Bearer $TOKEN"
# Get next 10
curl "http://localhost:8080/v1/mcp/services?page=1&size=10" \
-H "Authorization: Bearer $TOKEN"
Test 3: Get Full Service Details
curl http://localhost:8080/v1/mcp/services/user-service \
-H "Authorization: Bearer $TOKEN" | jq '.'
Test 4: Update Service
curl -X PUT http://localhost:8080/v1/mcp/services/user-service \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"displayName": "User Management Service (v2)",
"tags": ["users", "accounts", "v2", "enhanced"]
}'
Architecture
┌─────────────────────────────────────────────────────────┐
│ MCP Publishing Controller │
│ (7 REST endpoints for publication & management) │
└────────────────┬────────────────────────────────────────┘
│
├─→ RestToMcpConverter
│ (Scans Spring controllers)
│
├─→ McpToolService
│ (CRUD for MCP tools)
│
├─→ McpServiceRegistryRepository
│ (Service registry persistence)
│
├─→ McpTransportConfigRepository
│ (Transport configuration)
│
└─→ McpServerRepository
(Service provider instances)
│
↓
┌──────────────────────────┐
│ PostgreSQL Database │
│ (Service Registry) │
└──────────────────────────┘
✅ PRODUCTION READY