Merge pull request #1 from bsodfather/feat/crank-rebrand
Feat/crank rebrand
This commit is contained in:
+12
-12
@@ -1,13 +1,13 @@
|
|||||||
POSTGRES_DB=rmcp
|
POSTGRES_DB=crank
|
||||||
POSTGRES_USER=rmcp
|
POSTGRES_USER=crank
|
||||||
POSTGRES_PASSWORD=change-me
|
POSTGRES_PASSWORD=change-me
|
||||||
MCPAAS_DATABASE_URL=postgres://rmcp:change-me@postgres:5432/rmcp
|
CRANK_DATABASE_URL=postgres://crank:change-me@postgres:5432/crank
|
||||||
MCPAAS_STORAGE_ROOT=/var/lib/rmcp/storage
|
CRANK_STORAGE_ROOT=/var/lib/crank/storage
|
||||||
MCPAAS_PUBLISH_HOST=127.0.0.1
|
CRANK_PUBLISH_HOST=127.0.0.1
|
||||||
MCPAAS_ADMIN_BIND=0.0.0.0:3001
|
CRANK_ADMIN_BIND=0.0.0.0:3001
|
||||||
MCPAAS_MCP_BIND=0.0.0.0:3002
|
CRANK_MCP_BIND=0.0.0.0:3002
|
||||||
MCPAAS_MCP_REFRESH_MS=5000
|
CRANK_MCP_REFRESH_MS=5000
|
||||||
MCPAAS_LOG_LEVEL=info
|
CRANK_LOG_LEVEL=info
|
||||||
MCPAAS_SECRET_PROVIDER=env
|
CRANK_SECRET_PROVIDER=env
|
||||||
MCPAAS_PUBLIC_BASE_URL=https://rmcp.example.com
|
CRANK_PUBLIC_BASE_URL=https://crank.example.com
|
||||||
MCPAAS_MCP_PUBLIC_URL=https://rmcp.example.com/mcp
|
CRANK_MCP_PUBLIC_URL=https://crank.example.com/mcp
|
||||||
|
|||||||
@@ -19,18 +19,18 @@ jobs:
|
|||||||
postgres:
|
postgres:
|
||||||
image: postgres:16-alpine
|
image: postgres:16-alpine
|
||||||
env:
|
env:
|
||||||
POSTGRES_DB: rmcp_test
|
POSTGRES_DB: crank_test
|
||||||
POSTGRES_USER: postgres
|
POSTGRES_USER: postgres
|
||||||
POSTGRES_PASSWORD: postgres
|
POSTGRES_PASSWORD: postgres
|
||||||
ports:
|
ports:
|
||||||
- 5432:5432
|
- 5432:5432
|
||||||
options: >-
|
options: >-
|
||||||
--health-cmd "pg_isready -U postgres -d rmcp_test"
|
--health-cmd "pg_isready -U postgres -d crank_test"
|
||||||
--health-interval 10s
|
--health-interval 10s
|
||||||
--health-timeout 5s
|
--health-timeout 5s
|
||||||
--health-retries 5
|
--health-retries 5
|
||||||
env:
|
env:
|
||||||
TEST_DATABASE_URL: postgres://postgres:postgres@127.0.0.1:5432/rmcp_test
|
TEST_DATABASE_URL: postgres://postgres:postgres@127.0.0.1:5432/crank_test
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
|
|||||||
Generated
+136
-136
@@ -7,13 +7,13 @@ name = "admin-api"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"mcpaas-adapter-grpc",
|
"crank-adapter-grpc",
|
||||||
"mcpaas-core",
|
"crank-core",
|
||||||
"mcpaas-mapping",
|
"crank-mapping",
|
||||||
"mcpaas-proto",
|
"crank-proto",
|
||||||
"mcpaas-registry",
|
"crank-registry",
|
||||||
"mcpaas-runtime",
|
"crank-runtime",
|
||||||
"mcpaas-schema",
|
"crank-schema",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -211,6 +211,129 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crank-adapter-graphql"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"axum",
|
||||||
|
"crank-core",
|
||||||
|
"crank-mapping",
|
||||||
|
"reqwest",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crank-adapter-grpc"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
"crank-core",
|
||||||
|
"crank-proto",
|
||||||
|
"prost",
|
||||||
|
"prost-reflect",
|
||||||
|
"prost-types",
|
||||||
|
"protoc-bin-vendored",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
"tonic",
|
||||||
|
"tonic-prost",
|
||||||
|
"tonic-prost-build",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crank-adapter-rest"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"axum",
|
||||||
|
"crank-core",
|
||||||
|
"reqwest",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crank-core"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_yaml",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crank-mapping"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"crank-core",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_yaml",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crank-proto"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"crank-core",
|
||||||
|
"crank-schema",
|
||||||
|
"prost",
|
||||||
|
"prost-reflect",
|
||||||
|
"prost-types",
|
||||||
|
"serde",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crank-registry"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"crank-core",
|
||||||
|
"crank-mapping",
|
||||||
|
"crank-schema",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"sqlx",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crank-runtime"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"axum",
|
||||||
|
"crank-adapter-graphql",
|
||||||
|
"crank-adapter-grpc",
|
||||||
|
"crank-adapter-rest",
|
||||||
|
"crank-core",
|
||||||
|
"crank-mapping",
|
||||||
|
"crank-schema",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crank-schema"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"crank-core",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_yaml",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc"
|
name = "crc"
|
||||||
version = "3.4.0"
|
version = "3.4.0"
|
||||||
@@ -933,12 +1056,12 @@ name = "mcp-server"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"mcpaas-adapter-grpc",
|
"crank-adapter-grpc",
|
||||||
"mcpaas-core",
|
"crank-core",
|
||||||
"mcpaas-mapping",
|
"crank-mapping",
|
||||||
"mcpaas-registry",
|
"crank-registry",
|
||||||
"mcpaas-runtime",
|
"crank-runtime",
|
||||||
"mcpaas-schema",
|
"crank-schema",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -949,129 +1072,6 @@ dependencies = [
|
|||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mcpaas-adapter-graphql"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"axum",
|
|
||||||
"mcpaas-core",
|
|
||||||
"mcpaas-mapping",
|
|
||||||
"reqwest",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"thiserror",
|
|
||||||
"tokio",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mcpaas-adapter-grpc"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"base64",
|
|
||||||
"mcpaas-core",
|
|
||||||
"mcpaas-proto",
|
|
||||||
"prost",
|
|
||||||
"prost-reflect",
|
|
||||||
"prost-types",
|
|
||||||
"protoc-bin-vendored",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"thiserror",
|
|
||||||
"tokio",
|
|
||||||
"tonic",
|
|
||||||
"tonic-prost",
|
|
||||||
"tonic-prost-build",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mcpaas-adapter-rest"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"axum",
|
|
||||||
"mcpaas-core",
|
|
||||||
"reqwest",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"thiserror",
|
|
||||||
"tokio",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mcpaas-core"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"serde_yaml",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mcpaas-mapping"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"mcpaas-core",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"serde_yaml",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mcpaas-proto"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"mcpaas-core",
|
|
||||||
"mcpaas-schema",
|
|
||||||
"prost",
|
|
||||||
"prost-reflect",
|
|
||||||
"prost-types",
|
|
||||||
"serde",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mcpaas-registry"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"mcpaas-core",
|
|
||||||
"mcpaas-mapping",
|
|
||||||
"mcpaas-schema",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"sqlx",
|
|
||||||
"thiserror",
|
|
||||||
"tokio",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mcpaas-runtime"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"axum",
|
|
||||||
"mcpaas-adapter-graphql",
|
|
||||||
"mcpaas-adapter-grpc",
|
|
||||||
"mcpaas-adapter-rest",
|
|
||||||
"mcpaas-core",
|
|
||||||
"mcpaas-mapping",
|
|
||||||
"mcpaas-schema",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"thiserror",
|
|
||||||
"tokio",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mcpaas-schema"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"mcpaas-core",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"serde_yaml",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "md-5"
|
name = "md-5"
|
||||||
version = "0.10.6"
|
version = "0.10.6"
|
||||||
|
|||||||
+9
-9
@@ -2,15 +2,15 @@
|
|||||||
members = [
|
members = [
|
||||||
"apps/admin-api",
|
"apps/admin-api",
|
||||||
"apps/mcp-server",
|
"apps/mcp-server",
|
||||||
"crates/mcpaas-core",
|
"crates/crank-core",
|
||||||
"crates/mcpaas-schema",
|
"crates/crank-schema",
|
||||||
"crates/mcpaas-mapping",
|
"crates/crank-mapping",
|
||||||
"crates/mcpaas-proto",
|
"crates/crank-proto",
|
||||||
"crates/mcpaas-registry",
|
"crates/crank-registry",
|
||||||
"crates/mcpaas-runtime",
|
"crates/crank-runtime",
|
||||||
"crates/mcpaas-adapter-rest",
|
"crates/crank-adapter-rest",
|
||||||
"crates/mcpaas-adapter-graphql",
|
"crates/crank-adapter-graphql",
|
||||||
"crates/mcpaas-adapter-grpc",
|
"crates/crank-adapter-grpc",
|
||||||
]
|
]
|
||||||
resolver = "3"
|
resolver = "3"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
# MCPaaS
|
# Crank
|
||||||
|
|
||||||
MCPaaS - это low-code платформа для публикации внешних API в виде MCP tools без написания нового backend-обработчика под каждую интеграцию. Система предоставляет единый административный UI, в котором оператор может подключать REST, GraphQL и gRPC операции, настраивать маппинг входных и выходных данных, выполнять тестовый вызов и публиковать результат как MCP tool.
|

|
||||||
|
|
||||||
|
Crank - это low-code платформа для публикации внешних API в виде MCP tools без написания нового backend-обработчика под каждую интеграцию. Система предоставляет единый административный UI, в котором оператор может подключать REST, GraphQL и gRPC операции, настраивать маппинг входных и выходных данных, выполнять тестовый вызов и публиковать результат как MCP tool.
|
||||||
|
|
||||||
На текущем этапе репозиторий содержит проектную документацию и архитектурные решения, которые задают границы MVP и подход к реализации.
|
На текущем этапе репозиторий содержит проектную документацию и архитектурные решения, которые задают границы MVP и подход к реализации.
|
||||||
|
|
||||||
|
|||||||
@@ -2,17 +2,17 @@
|
|||||||
|
|
||||||
## Current
|
## Current
|
||||||
|
|
||||||
### `feat/ui-concept-alignment`
|
### `feat/crank-rebrand`
|
||||||
|
|
||||||
Status: completed
|
Status: completed
|
||||||
|
|
||||||
DoD:
|
DoD:
|
||||||
|
|
||||||
- shell и create flow визуально опираются на утвержденный concept
|
- проект переименован в `Crank` в документации, UI и package metadata
|
||||||
- sidebar, topbar и page header выглядят как единая продуктовая система
|
- workspace и crate package names согласованы с новым брендом
|
||||||
- create page больше не выглядит как длинная сырая форма, а как step-based contract builder
|
- `README.md` использует `Crank.png` как главное изображение
|
||||||
- кодовые JSON и mapping поля имеют отдельную визуальную подачу
|
- `origin` указывает на `git@github.com:bsodfather/crank.git`
|
||||||
- UI build и tests остаются зелеными после выравнивания под concept
|
- Rust workspace и UI build остаются зелеными
|
||||||
|
|
||||||
## Next
|
## Next
|
||||||
|
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ version.workspace = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
axum.workspace = true
|
axum.workspace = true
|
||||||
mcpaas-core = { path = "../../crates/mcpaas-core" }
|
crank-core = { path = "../../crates/crank-core" }
|
||||||
mcpaas-mapping = { path = "../../crates/mcpaas-mapping" }
|
crank-mapping = { path = "../../crates/crank-mapping" }
|
||||||
mcpaas-proto = { path = "../../crates/mcpaas-proto" }
|
crank-proto = { path = "../../crates/crank-proto" }
|
||||||
mcpaas-registry = { path = "../../crates/mcpaas-registry" }
|
crank-registry = { path = "../../crates/crank-registry" }
|
||||||
mcpaas-runtime = { path = "../../crates/mcpaas-runtime" }
|
crank-runtime = { path = "../../crates/crank-runtime" }
|
||||||
mcpaas-schema = { path = "../../crates/mcpaas-schema" }
|
crank-schema = { path = "../../crates/crank-schema" }
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
serde_yaml.workspace = true
|
serde_yaml.workspace = true
|
||||||
@@ -24,6 +24,6 @@ tracing-subscriber.workspace = true
|
|||||||
uuid.workspace = true
|
uuid.workspace = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
mcpaas-adapter-grpc = { path = "../../crates/mcpaas-adapter-grpc", features = ["test-support"] }
|
crank-adapter-grpc = { path = "../../crates/crank-adapter-grpc", features = ["test-support"] }
|
||||||
reqwest.workspace = true
|
reqwest.workspace = true
|
||||||
sqlx.workspace = true
|
sqlx.workspace = true
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ WORKDIR /app
|
|||||||
|
|
||||||
COPY --from=builder /app/target/release/admin-api /usr/local/bin/admin-api
|
COPY --from=builder /app/target/release/admin-api /usr/local/bin/admin-api
|
||||||
|
|
||||||
ENV MCPAAS_ADMIN_BIND=0.0.0.0:3001
|
ENV CRANK_ADMIN_BIND=0.0.0.0:3001
|
||||||
|
|
||||||
EXPOSE 3001
|
EXPOSE 3001
|
||||||
|
|
||||||
|
|||||||
@@ -80,14 +80,14 @@ mod tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
use axum::{Json, Router, routing::post};
|
use axum::{Json, Router, routing::post};
|
||||||
use mcpaas_adapter_grpc::test_support as grpc_test_support;
|
use crank_adapter_grpc::test_support as grpc_test_support;
|
||||||
use mcpaas_core::{
|
use crank_core::{
|
||||||
DescriptorId, ExecutionConfig, GraphqlOperationType, GraphqlTarget, GrpcTarget, HttpMethod,
|
DescriptorId, ExecutionConfig, GraphqlOperationType, GraphqlTarget, GrpcTarget, HttpMethod,
|
||||||
Protocol, RestTarget, Target, ToolDescription,
|
Protocol, RestTarget, Target, ToolDescription,
|
||||||
};
|
};
|
||||||
use mcpaas_mapping::{MappingRule, MappingSet};
|
use crank_mapping::{MappingRule, MappingSet};
|
||||||
use mcpaas_registry::PostgresRegistry;
|
use crank_registry::PostgresRegistry;
|
||||||
use mcpaas_schema::{Schema, SchemaKind};
|
use crank_schema::{Schema, SchemaKind};
|
||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
use sqlx::{Executor, postgres::PgPoolOptions};
|
use sqlx::{Executor, postgres::PgPoolOptions};
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
@@ -621,7 +621,7 @@ mod tests {
|
|||||||
|
|
||||||
async fn test_registry() -> PostgresRegistry {
|
async fn test_registry() -> PostgresRegistry {
|
||||||
let database_url = env::var("TEST_DATABASE_URL")
|
let database_url = env::var("TEST_DATABASE_URL")
|
||||||
.unwrap_or_else(|_| "postgres://rmcp:rmcp@127.0.0.1:5432/rmcp".to_owned());
|
.unwrap_or_else(|_| "postgres://crank:crank@127.0.0.1:5432/crank".to_owned());
|
||||||
let admin_pool = PgPoolOptions::new()
|
let admin_pool = PgPoolOptions::new()
|
||||||
.max_connections(1)
|
.max_connections(1)
|
||||||
.connect(&database_url)
|
.connect(&database_url)
|
||||||
@@ -648,7 +648,7 @@ mod tests {
|
|||||||
|
|
||||||
fn test_storage_root(name: &str) -> std::path::PathBuf {
|
fn test_storage_root(name: &str) -> std::path::PathBuf {
|
||||||
env::temp_dir().join(format!(
|
env::temp_dir().join(format!(
|
||||||
"rmcp_admin_api_{name}_{}_{}",
|
"crank_admin_api_{name}_{}_{}",
|
||||||
std::process::id(),
|
std::process::id(),
|
||||||
SystemTime::now()
|
SystemTime::now()
|
||||||
.duration_since(UNIX_EPOCH)
|
.duration_since(UNIX_EPOCH)
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ use axum::{
|
|||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
response::{IntoResponse, Response},
|
response::{IntoResponse, Response},
|
||||||
};
|
};
|
||||||
use mcpaas_mapping::MappingError;
|
use crank_mapping::MappingError;
|
||||||
use mcpaas_registry::RegistryError;
|
use crank_registry::RegistryError;
|
||||||
use mcpaas_runtime::RuntimeError;
|
use crank_runtime::RuntimeError;
|
||||||
use mcpaas_schema::SchemaError;
|
use crank_schema::SchemaError;
|
||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tracing::{error, warn};
|
use tracing::{error, warn};
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ mod storage;
|
|||||||
|
|
||||||
use std::{env, net::SocketAddr, path::PathBuf};
|
use std::{env, net::SocketAddr, path::PathBuf};
|
||||||
|
|
||||||
use mcpaas_registry::PostgresRegistry;
|
use crank_registry::PostgresRegistry;
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
@@ -17,16 +17,15 @@ use crate::{app::build_app, service::AdminService, state::AppState};
|
|||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
.with_env_filter(
|
.with_env_filter(
|
||||||
env::var("MCPAAS_LOG_LEVEL")
|
env::var("CRANK_LOG_LEVEL").unwrap_or_else(|_| "admin_api=info,tower_http=info".into()),
|
||||||
.unwrap_or_else(|_| "admin_api=info,tower_http=info".into()),
|
|
||||||
)
|
)
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
let database_url = env::var("MCPAAS_DATABASE_URL")?;
|
let database_url = env::var("CRANK_DATABASE_URL")?;
|
||||||
let storage_root = PathBuf::from(
|
let storage_root = PathBuf::from(
|
||||||
env::var("MCPAAS_STORAGE_ROOT").unwrap_or_else(|_| "/var/lib/rmcp/storage".into()),
|
env::var("CRANK_STORAGE_ROOT").unwrap_or_else(|_| "/var/lib/crank/storage".into()),
|
||||||
);
|
);
|
||||||
let bind_addr = env::var("MCPAAS_ADMIN_BIND").unwrap_or_else(|_| "0.0.0.0:3001".into());
|
let bind_addr = env::var("CRANK_ADMIN_BIND").unwrap_or_else(|_| "0.0.0.0:3001".into());
|
||||||
let socket_addr: SocketAddr = bind_addr.parse()?;
|
let socket_addr: SocketAddr = bind_addr.parse()?;
|
||||||
let registry = PostgresRegistry::connect(&database_url).await?;
|
let registry = PostgresRegistry::connect(&database_url).await?;
|
||||||
let state = AppState {
|
let state = AppState {
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ pub async fn upload_input_json(
|
|||||||
.service
|
.service
|
||||||
.save_json_sample(
|
.save_json_sample(
|
||||||
&operation_id.as_str().into(),
|
&operation_id.as_str().into(),
|
||||||
mcpaas_registry::SampleKind::InputJson,
|
crank_registry::SampleKind::InputJson,
|
||||||
&payload,
|
&payload,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
@@ -117,7 +117,7 @@ pub async fn upload_output_json(
|
|||||||
.service
|
.service
|
||||||
.save_json_sample(
|
.save_json_sample(
|
||||||
&operation_id.as_str().into(),
|
&operation_id.as_str().into(),
|
||||||
mcpaas_registry::SampleKind::OutputJson,
|
crank_registry::SampleKind::OutputJson,
|
||||||
&payload,
|
&payload,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use mcpaas_core::{
|
use crank_core::{
|
||||||
AuthConfig, AuthKind, AuthProfile, AuthProfileId, ConfigExport, ExportMode, GeneratedDraft,
|
AuthConfig, AuthKind, AuthProfile, AuthProfileId, ConfigExport, ExportMode, GeneratedDraft,
|
||||||
GeneratedDraftStatus, OperationId, OperationStatus, Protocol, SampleId, Samples, Target,
|
GeneratedDraftStatus, OperationId, OperationStatus, Protocol, SampleId, Samples, Target,
|
||||||
};
|
};
|
||||||
use mcpaas_mapping::{JsonPathRoot, MappingSet, infer_mapping_from_samples};
|
use crank_mapping::{JsonPathRoot, MappingSet, infer_mapping_from_samples};
|
||||||
use mcpaas_proto::{ProtoService, services_from_descriptor_set_bytes};
|
use crank_proto::{ProtoService, services_from_descriptor_set_bytes};
|
||||||
use mcpaas_registry::{
|
use crank_registry::{
|
||||||
CreateVersionRequest, OperationSampleMetadata, OperationSummary, OperationVersionRecord,
|
CreateVersionRequest, OperationSampleMetadata, OperationSummary, OperationVersionRecord,
|
||||||
PostgresRegistry, PublishRequest, RegistryOperation, SampleKind, SaveAuthProfileRequest,
|
PostgresRegistry, PublishRequest, RegistryOperation, SampleKind, SaveAuthProfileRequest,
|
||||||
SaveDescriptorMetadataRequest, SaveSampleMetadataRequest,
|
SaveDescriptorMetadataRequest, SaveSampleMetadataRequest,
|
||||||
};
|
};
|
||||||
use mcpaas_runtime::{PreparedRequest, RuntimeError, RuntimeExecutor, RuntimeOperation};
|
use crank_runtime::{PreparedRequest, RuntimeError, RuntimeExecutor, RuntimeOperation};
|
||||||
use mcpaas_schema::Schema;
|
use crank_schema::Schema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
use time::{OffsetDateTime, format_description::well_known::Rfc3339};
|
use time::{OffsetDateTime, format_description::well_known::Rfc3339};
|
||||||
@@ -38,8 +38,8 @@ pub struct OperationPayload {
|
|||||||
pub output_schema: Schema,
|
pub output_schema: Schema,
|
||||||
pub input_mapping: MappingSet,
|
pub input_mapping: MappingSet,
|
||||||
pub output_mapping: MappingSet,
|
pub output_mapping: MappingSet,
|
||||||
pub execution_config: mcpaas_core::ExecutionConfig,
|
pub execution_config: crank_core::ExecutionConfig,
|
||||||
pub tool_description: mcpaas_core::ToolDescription,
|
pub tool_description: crank_core::ToolDescription,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
@@ -395,13 +395,13 @@ impl AdminService {
|
|||||||
|
|
||||||
let services = services_from_descriptor_set_bytes(payload)
|
let services = services_from_descriptor_set_bytes(payload)
|
||||||
.map_err(|error| ApiError::validation(error.to_string()))?;
|
.map_err(|error| ApiError::validation(error.to_string()))?;
|
||||||
let descriptor_id = mcpaas_core::DescriptorId::new(new_prefixed_id("desc"));
|
let descriptor_id = crank_core::DescriptorId::new(new_prefixed_id("desc"));
|
||||||
let storage_ref = self
|
let storage_ref = self
|
||||||
.storage
|
.storage
|
||||||
.write_descriptor(
|
.write_descriptor(
|
||||||
operation_id,
|
operation_id,
|
||||||
summary.current_draft_version,
|
summary.current_draft_version,
|
||||||
mcpaas_registry::DescriptorKind::DescriptorSet,
|
crank_registry::DescriptorKind::DescriptorSet,
|
||||||
&descriptor_id,
|
&descriptor_id,
|
||||||
source_name,
|
source_name,
|
||||||
payload,
|
payload,
|
||||||
@@ -410,11 +410,11 @@ impl AdminService {
|
|||||||
|
|
||||||
self.registry
|
self.registry
|
||||||
.save_descriptor_metadata(SaveDescriptorMetadataRequest {
|
.save_descriptor_metadata(SaveDescriptorMetadataRequest {
|
||||||
descriptor: &mcpaas_registry::DescriptorMetadata {
|
descriptor: &crank_registry::DescriptorMetadata {
|
||||||
id: descriptor_id.clone(),
|
id: descriptor_id.clone(),
|
||||||
operation_id: Some(operation_id.clone()),
|
operation_id: Some(operation_id.clone()),
|
||||||
version: Some(summary.current_draft_version),
|
version: Some(summary.current_draft_version),
|
||||||
descriptor_kind: mcpaas_registry::DescriptorKind::DescriptorSet,
|
descriptor_kind: crank_registry::DescriptorKind::DescriptorSet,
|
||||||
storage_ref,
|
storage_ref,
|
||||||
source_name: source_name.map(ToOwned::to_owned),
|
source_name: source_name.map(ToOwned::to_owned),
|
||||||
package_index: Some(
|
package_index: Some(
|
||||||
@@ -452,13 +452,13 @@ impl AdminService {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let descriptor_id = mcpaas_core::DescriptorId::new(new_prefixed_id("desc"));
|
let descriptor_id = crank_core::DescriptorId::new(new_prefixed_id("desc"));
|
||||||
let storage_ref = self
|
let storage_ref = self
|
||||||
.storage
|
.storage
|
||||||
.write_descriptor(
|
.write_descriptor(
|
||||||
operation_id,
|
operation_id,
|
||||||
summary.current_draft_version,
|
summary.current_draft_version,
|
||||||
mcpaas_registry::DescriptorKind::ProtoUpload,
|
crank_registry::DescriptorKind::ProtoUpload,
|
||||||
&descriptor_id,
|
&descriptor_id,
|
||||||
source_name,
|
source_name,
|
||||||
payload,
|
payload,
|
||||||
@@ -467,11 +467,11 @@ impl AdminService {
|
|||||||
|
|
||||||
self.registry
|
self.registry
|
||||||
.save_descriptor_metadata(SaveDescriptorMetadataRequest {
|
.save_descriptor_metadata(SaveDescriptorMetadataRequest {
|
||||||
descriptor: &mcpaas_registry::DescriptorMetadata {
|
descriptor: &crank_registry::DescriptorMetadata {
|
||||||
id: descriptor_id.clone(),
|
id: descriptor_id.clone(),
|
||||||
operation_id: Some(operation_id.clone()),
|
operation_id: Some(operation_id.clone()),
|
||||||
version: Some(summary.current_draft_version),
|
version: Some(summary.current_draft_version),
|
||||||
descriptor_kind: mcpaas_registry::DescriptorKind::ProtoUpload,
|
descriptor_kind: crank_registry::DescriptorKind::ProtoUpload,
|
||||||
storage_ref,
|
storage_ref,
|
||||||
source_name: source_name.map(ToOwned::to_owned),
|
source_name: source_name.map(ToOwned::to_owned),
|
||||||
package_index: None,
|
package_index: None,
|
||||||
@@ -513,7 +513,7 @@ impl AdminService {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.rev()
|
.rev()
|
||||||
.find(|descriptor| {
|
.find(|descriptor| {
|
||||||
descriptor.descriptor_kind == mcpaas_registry::DescriptorKind::DescriptorSet
|
descriptor.descriptor_kind == crank_registry::DescriptorKind::DescriptorSet
|
||||||
})
|
})
|
||||||
.ok_or_else(|| ApiError::not_found("descriptor set was not uploaded"))?;
|
.ok_or_else(|| ApiError::not_found("descriptor set was not uploaded"))?;
|
||||||
let bytes = self.storage.read_bytes(&descriptor.storage_ref).await?;
|
let bytes = self.storage.read_bytes(&descriptor.storage_ref).await?;
|
||||||
@@ -809,10 +809,10 @@ impl AdminService {
|
|||||||
fn build_request_preview(
|
fn build_request_preview(
|
||||||
mapping: &MappingSet,
|
mapping: &MappingSet,
|
||||||
input: &Value,
|
input: &Value,
|
||||||
) -> Result<Value, mcpaas_mapping::MappingError> {
|
) -> Result<Value, crank_mapping::MappingError> {
|
||||||
let mapped = mapping.apply(&json!({ "mcp": input }))?;
|
let mapped = mapping.apply(&json!({ "mcp": input }))?;
|
||||||
let prepared = PreparedRequest::from_mapping_output(&mapped).map_err(|error| {
|
let prepared = PreparedRequest::from_mapping_output(&mapped).map_err(|error| {
|
||||||
mcpaas_mapping::MappingError::InvalidJsonPath {
|
crank_mapping::MappingError::InvalidJsonPath {
|
||||||
path: error.to_string(),
|
path: error.to_string(),
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
@@ -890,9 +890,9 @@ fn proto_service_summary(service: ProtoService) -> Result<GrpcServiceSummary, Ap
|
|||||||
Ok(GrpcMethodSummary {
|
Ok(GrpcMethodSummary {
|
||||||
name: method.name.clone(),
|
name: method.name.clone(),
|
||||||
kind: "unary".to_owned(),
|
kind: "unary".to_owned(),
|
||||||
input_schema: mcpaas_proto::message_to_schema(&method.input)
|
input_schema: crank_proto::message_to_schema(&method.input)
|
||||||
.map_err(|error| ApiError::validation(error.to_string()))?,
|
.map_err(|error| ApiError::validation(error.to_string()))?,
|
||||||
output_schema: mcpaas_proto::message_to_schema(&method.output)
|
output_schema: crank_proto::message_to_schema(&method.output)
|
||||||
.map_err(|error| ApiError::validation(error.to_string()))?,
|
.map_err(|error| ApiError::validation(error.to_string()))?,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use mcpaas_core::{DescriptorId, OperationId, SampleId};
|
use crank_core::{DescriptorId, OperationId, SampleId};
|
||||||
use mcpaas_registry::{DescriptorKind, SampleKind};
|
use crank_registry::{DescriptorKind, SampleKind};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ version.workspace = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
axum.workspace = true
|
axum.workspace = true
|
||||||
mcpaas-registry = { path = "../../crates/mcpaas-registry" }
|
crank-registry = { path = "../../crates/crank-registry" }
|
||||||
mcpaas-runtime = { path = "../../crates/mcpaas-runtime" }
|
crank-runtime = { path = "../../crates/crank-runtime" }
|
||||||
mcpaas-schema = { path = "../../crates/mcpaas-schema" }
|
crank-schema = { path = "../../crates/crank-schema" }
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
tokio = { workspace = true, features = ["sync"] }
|
tokio = { workspace = true, features = ["sync"] }
|
||||||
@@ -18,9 +18,9 @@ tracing-subscriber.workspace = true
|
|||||||
uuid.workspace = true
|
uuid.workspace = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
mcpaas-adapter-grpc = { path = "../../crates/mcpaas-adapter-grpc", features = ["test-support"] }
|
crank-adapter-grpc = { path = "../../crates/crank-adapter-grpc", features = ["test-support"] }
|
||||||
mcpaas-core = { path = "../../crates/mcpaas-core" }
|
crank-core = { path = "../../crates/crank-core" }
|
||||||
mcpaas-mapping = { path = "../../crates/mcpaas-mapping" }
|
crank-mapping = { path = "../../crates/crank-mapping" }
|
||||||
mcpaas-schema = { path = "../../crates/mcpaas-schema" }
|
crank-schema = { path = "../../crates/crank-schema" }
|
||||||
reqwest.workspace = true
|
reqwest.workspace = true
|
||||||
sqlx.workspace = true
|
sqlx.workspace = true
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ WORKDIR /app
|
|||||||
|
|
||||||
COPY --from=builder /app/target/release/mcp-server /usr/local/bin/mcp-server
|
COPY --from=builder /app/target/release/mcp-server /usr/local/bin/mcp-server
|
||||||
|
|
||||||
ENV MCPAAS_MCP_BIND=0.0.0.0:3002
|
ENV CRANK_MCP_BIND=0.0.0.0:3002
|
||||||
|
|
||||||
EXPOSE 3002
|
EXPOSE 3002
|
||||||
|
|
||||||
|
|||||||
+13
-13
@@ -10,8 +10,8 @@ use axum::{
|
|||||||
response::{IntoResponse, Response},
|
response::{IntoResponse, Response},
|
||||||
routing::get,
|
routing::get,
|
||||||
};
|
};
|
||||||
use mcpaas_registry::{PostgresRegistry, RegistryOperation};
|
use crank_registry::{PostgresRegistry, RegistryOperation};
|
||||||
use mcpaas_runtime::{RuntimeError, RuntimeExecutor, RuntimeOperation};
|
use crank_runtime::{RuntimeError, RuntimeExecutor, RuntimeOperation};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
|
|
||||||
@@ -312,7 +312,7 @@ async fn handle_initialize(state: Arc<AppState>, message: &Value) -> Response {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"serverInfo": {
|
"serverInfo": {
|
||||||
"name": "rmcp-mcp-server",
|
"name": "crank-mcp-server",
|
||||||
"version": env!("CARGO_PKG_VERSION")
|
"version": env!("CARGO_PKG_VERSION")
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
@@ -480,9 +480,9 @@ fn tool_definition(operation: &RegistryOperation) -> Value {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn schema_to_json_schema(schema: &mcpaas_schema::Schema) -> Value {
|
fn schema_to_json_schema(schema: &crank_schema::Schema) -> Value {
|
||||||
match schema.kind {
|
match schema.kind {
|
||||||
mcpaas_schema::SchemaKind::Object => {
|
crank_schema::SchemaKind::Object => {
|
||||||
let mut properties = serde_json::Map::new();
|
let mut properties = serde_json::Map::new();
|
||||||
let mut required = Vec::new();
|
let mut required = Vec::new();
|
||||||
|
|
||||||
@@ -500,7 +500,7 @@ fn schema_to_json_schema(schema: &mcpaas_schema::Schema) -> Value {
|
|||||||
"required": required
|
"required": required
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
mcpaas_schema::SchemaKind::Array => json!({
|
crank_schema::SchemaKind::Array => json!({
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": schema
|
"items": schema
|
||||||
.items
|
.items
|
||||||
@@ -508,16 +508,16 @@ fn schema_to_json_schema(schema: &mcpaas_schema::Schema) -> Value {
|
|||||||
.map(schema_to_json_schema)
|
.map(schema_to_json_schema)
|
||||||
.unwrap_or_else(|| json!({}))
|
.unwrap_or_else(|| json!({}))
|
||||||
}),
|
}),
|
||||||
mcpaas_schema::SchemaKind::String => json!({ "type": "string" }),
|
crank_schema::SchemaKind::String => json!({ "type": "string" }),
|
||||||
mcpaas_schema::SchemaKind::Integer => json!({ "type": "integer" }),
|
crank_schema::SchemaKind::Integer => json!({ "type": "integer" }),
|
||||||
mcpaas_schema::SchemaKind::Number => json!({ "type": "number" }),
|
crank_schema::SchemaKind::Number => json!({ "type": "number" }),
|
||||||
mcpaas_schema::SchemaKind::Boolean => json!({ "type": "boolean" }),
|
crank_schema::SchemaKind::Boolean => json!({ "type": "boolean" }),
|
||||||
mcpaas_schema::SchemaKind::Enum => json!({
|
crank_schema::SchemaKind::Enum => json!({
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": schema.enum_values
|
"enum": schema.enum_values
|
||||||
}),
|
}),
|
||||||
mcpaas_schema::SchemaKind::Null => json!({ "type": "null" }),
|
crank_schema::SchemaKind::Null => json!({ "type": "null" }),
|
||||||
mcpaas_schema::SchemaKind::Oneof => json!({
|
crank_schema::SchemaKind::Oneof => json!({
|
||||||
"anyOf": schema.variants.iter().map(schema_to_json_schema).collect::<Vec<_>>()
|
"anyOf": schema.variants.iter().map(schema_to_json_schema).collect::<Vec<_>>()
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use std::{
|
|||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
use mcpaas_registry::{PostgresRegistry, RegistryError, RegistryOperation};
|
use crank_registry::{PostgresRegistry, RegistryError, RegistryOperation};
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
|
|||||||
+17
-17
@@ -5,7 +5,7 @@ mod session;
|
|||||||
|
|
||||||
use std::{env, net::SocketAddr, time::Duration};
|
use std::{env, net::SocketAddr, time::Duration};
|
||||||
|
|
||||||
use mcpaas_registry::PostgresRegistry;
|
use crank_registry::PostgresRegistry;
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
@@ -15,15 +15,15 @@ use crate::app::build_app;
|
|||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
.with_env_filter(
|
.with_env_filter(
|
||||||
env::var("MCPAAS_LOG_LEVEL")
|
env::var("CRANK_LOG_LEVEL")
|
||||||
.unwrap_or_else(|_| "mcp_server=info,tower_http=info".into()),
|
.unwrap_or_else(|_| "mcp_server=info,tower_http=info".into()),
|
||||||
)
|
)
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
let database_url = env::var("MCPAAS_DATABASE_URL")?;
|
let database_url = env::var("CRANK_DATABASE_URL")?;
|
||||||
let bind_addr = env::var("MCPAAS_MCP_BIND").unwrap_or_else(|_| "0.0.0.0:3002".into());
|
let bind_addr = env::var("CRANK_MCP_BIND").unwrap_or_else(|_| "0.0.0.0:3002".into());
|
||||||
let public_base_url = env::var("MCPAAS_PUBLIC_BASE_URL").ok();
|
let public_base_url = env::var("CRANK_PUBLIC_BASE_URL").ok();
|
||||||
let refresh_interval = env::var("MCPAAS_MCP_REFRESH_MS")
|
let refresh_interval = env::var("CRANK_MCP_REFRESH_MS")
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|value| value.parse::<u64>().ok())
|
.and_then(|value| value.parse::<u64>().ok())
|
||||||
.map(Duration::from_millis)
|
.map(Duration::from_millis)
|
||||||
@@ -49,14 +49,14 @@ mod tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
use axum::{Json, Router, http::header, routing::post};
|
use axum::{Json, Router, http::header, routing::post};
|
||||||
use mcpaas_adapter_grpc::test_support as grpc_test_support;
|
use crank_adapter_grpc::test_support as grpc_test_support;
|
||||||
use mcpaas_core::{
|
use crank_core::{
|
||||||
DescriptorId, ExecutionConfig, GraphqlOperationType, GraphqlTarget, GrpcTarget, HttpMethod,
|
DescriptorId, ExecutionConfig, GraphqlOperationType, GraphqlTarget, GrpcTarget, HttpMethod,
|
||||||
Operation, OperationId, OperationStatus, Protocol, RestTarget, Target, ToolDescription,
|
Operation, OperationId, OperationStatus, Protocol, RestTarget, Target, ToolDescription,
|
||||||
};
|
};
|
||||||
use mcpaas_mapping::{MappingRule, MappingSet};
|
use crank_mapping::{MappingRule, MappingSet};
|
||||||
use mcpaas_registry::{PostgresRegistry, PublishRequest};
|
use crank_registry::{PostgresRegistry, PublishRequest};
|
||||||
use mcpaas_schema::{Schema, SchemaKind};
|
use crank_schema::{Schema, SchemaKind};
|
||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
use sqlx::{Executor, postgres::PgPoolOptions};
|
use sqlx::{Executor, postgres::PgPoolOptions};
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
@@ -86,7 +86,7 @@ mod tests {
|
|||||||
let base_url = spawn_mcp_server(build_app(
|
let base_url = spawn_mcp_server(build_app(
|
||||||
registry,
|
registry,
|
||||||
Duration::from_millis(0),
|
Duration::from_millis(0),
|
||||||
Some("https://rmcp.example.com".to_owned()),
|
Some("https://crank.example.com".to_owned()),
|
||||||
))
|
))
|
||||||
.await;
|
.await;
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
@@ -153,7 +153,7 @@ mod tests {
|
|||||||
let base_url = spawn_mcp_server(build_app(
|
let base_url = spawn_mcp_server(build_app(
|
||||||
registry,
|
registry,
|
||||||
Duration::from_millis(0),
|
Duration::from_millis(0),
|
||||||
Some("https://rmcp.example.com".to_owned()),
|
Some("https://crank.example.com".to_owned()),
|
||||||
))
|
))
|
||||||
.await;
|
.await;
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
@@ -207,7 +207,7 @@ mod tests {
|
|||||||
let base_url = spawn_mcp_server(build_app(
|
let base_url = spawn_mcp_server(build_app(
|
||||||
registry,
|
registry,
|
||||||
Duration::from_millis(0),
|
Duration::from_millis(0),
|
||||||
Some("https://rmcp.example.com".to_owned()),
|
Some("https://crank.example.com".to_owned()),
|
||||||
))
|
))
|
||||||
.await;
|
.await;
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
@@ -244,7 +244,7 @@ mod tests {
|
|||||||
let base_url = spawn_mcp_server(build_app(
|
let base_url = spawn_mcp_server(build_app(
|
||||||
registry,
|
registry,
|
||||||
Duration::from_millis(0),
|
Duration::from_millis(0),
|
||||||
Some("https://rmcp.example.com".to_owned()),
|
Some("https://crank.example.com".to_owned()),
|
||||||
))
|
))
|
||||||
.await;
|
.await;
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
@@ -297,7 +297,7 @@ mod tests {
|
|||||||
let base_url = spawn_mcp_server(build_app(
|
let base_url = spawn_mcp_server(build_app(
|
||||||
registry.clone(),
|
registry.clone(),
|
||||||
Duration::from_millis(0),
|
Duration::from_millis(0),
|
||||||
Some("https://rmcp.example.com".to_owned()),
|
Some("https://crank.example.com".to_owned()),
|
||||||
))
|
))
|
||||||
.await;
|
.await;
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
@@ -479,7 +479,7 @@ mod tests {
|
|||||||
|
|
||||||
async fn test_registry() -> PostgresRegistry {
|
async fn test_registry() -> PostgresRegistry {
|
||||||
let database_url = env::var("TEST_DATABASE_URL")
|
let database_url = env::var("TEST_DATABASE_URL")
|
||||||
.unwrap_or_else(|_| "postgres://rmcp:rmcp@127.0.0.1:5432/rmcp".to_owned());
|
.unwrap_or_else(|_| "postgres://crank:crank@127.0.0.1:5432/crank".to_owned());
|
||||||
let admin_pool = PgPoolOptions::new()
|
let admin_pool = PgPoolOptions::new()
|
||||||
.max_connections(1)
|
.max_connections(1)
|
||||||
.connect(&database_url)
|
.connect(&database_url)
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>RMCP Console</title>
|
<title>Crank Console</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "rmcp-ui",
|
"name": "crank-ui",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "rmcp-ui",
|
"name": "crank-ui",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hookform/resolvers": "^5.2.2",
|
"@hookform/resolvers": "^5.2.2",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "rmcp-ui",
|
"name": "crank-ui",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ describe("buildOperationPayload", () => {
|
|||||||
...defaultOperationFormValues,
|
...defaultOperationFormValues,
|
||||||
restStaticHeadersText: JSON.stringify(
|
restStaticHeadersText: JSON.stringify(
|
||||||
{
|
{
|
||||||
"x-app-source": "rmcp",
|
"x-app-source": "crank",
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
2,
|
2,
|
||||||
@@ -26,7 +26,7 @@ describe("buildOperationPayload", () => {
|
|||||||
expect(payload.target.kind).toBe("rest");
|
expect(payload.target.kind).toBe("rest");
|
||||||
expect(payload.target.method).toBe("POST");
|
expect(payload.target.method).toBe("POST");
|
||||||
expect(payload.target.static_headers).toEqual({
|
expect(payload.target.static_headers).toEqual({
|
||||||
"x-app-source": "rmcp",
|
"x-app-source": "crank",
|
||||||
});
|
});
|
||||||
expect(payload.execution_config.headers).toEqual({
|
expect(payload.execution_config.headers).toEqual({
|
||||||
"x-trace-id": "trace-123",
|
"x-trace-id": "trace-123",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
|||||||
import { useMutation } from "@tanstack/react-query";
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import { useEffect, useMemo, useRef } from "react";
|
import { useEffect, useMemo, useRef } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
|
import { createPortal } from "react-dom";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
import { createOperation } from "../../entities/operation/api";
|
import { createOperation } from "../../entities/operation/api";
|
||||||
@@ -195,7 +196,11 @@ function bytesToBase64(buffer: ArrayBuffer) {
|
|||||||
return window.btoa(binary);
|
return window.btoa(binary);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OperationForm() {
|
type OperationFormProps = {
|
||||||
|
actionBarContainerId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function OperationForm({ actionBarContainerId }: OperationFormProps) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const form = useForm<OperationFormValues>({
|
const form = useForm<OperationFormValues>({
|
||||||
defaultValues: defaultOperationFormValues,
|
defaultValues: defaultOperationFormValues,
|
||||||
@@ -236,6 +241,9 @@ export function OperationForm() {
|
|||||||
}
|
}
|
||||||
}, [activeProtocol]);
|
}, [activeProtocol]);
|
||||||
|
|
||||||
|
const actionBarContainer =
|
||||||
|
actionBarContainerId === undefined ? null : document.getElementById(actionBarContainerId);
|
||||||
|
|
||||||
async function handleDescriptorFileChange(file: File | undefined) {
|
async function handleDescriptorFileChange(file: File | undefined) {
|
||||||
if (file === undefined) {
|
if (file === undefined) {
|
||||||
return;
|
return;
|
||||||
@@ -339,174 +347,194 @@ export function OperationForm() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<>
|
||||||
className="builder-stack"
|
<form
|
||||||
onSubmit={form.handleSubmit((values) => {
|
className="builder-stack"
|
||||||
creationMutation.mutate(values);
|
id="operation-create-form"
|
||||||
})}
|
onSubmit={form.handleSubmit((values) => {
|
||||||
>
|
creationMutation.mutate(values);
|
||||||
<section className="builder-card">
|
})}
|
||||||
<header className="builder-card-header">
|
>
|
||||||
<div>
|
<div className="builder-content">
|
||||||
<h2>1 — Protocol</h2>
|
<section className="builder-card">
|
||||||
<p>One tool maps to exactly one upstream method.</p>
|
<header className="builder-card-header">
|
||||||
</div>
|
<div>
|
||||||
</header>
|
<h2>1 — Protocol</h2>
|
||||||
<div className="builder-card-body">
|
<p>One tool maps to exactly one upstream method.</p>
|
||||||
<div className="proto-grid">
|
</div>
|
||||||
{protocolCards.map((card) => {
|
</header>
|
||||||
const isSelected = activeProtocol === card.protocol;
|
<div className="builder-card-body">
|
||||||
const selectedClassName = isSelected
|
<div className="proto-grid">
|
||||||
? `proto-card selected-${card.protocol === "graphql" ? "gql" : card.protocol}`
|
{protocolCards.map((card) => {
|
||||||
: "proto-card";
|
const isSelected = activeProtocol === card.protocol;
|
||||||
|
const selectedClassName = isSelected
|
||||||
|
? `proto-card selected-${card.protocol === "graphql" ? "gql" : card.protocol}`
|
||||||
|
: "proto-card";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
className={selectedClassName}
|
className={selectedClassName}
|
||||||
key={card.protocol}
|
key={card.protocol}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
form.setValue("protocol", card.protocol, {
|
form.setValue("protocol", card.protocol, {
|
||||||
shouldDirty: true,
|
shouldDirty: true,
|
||||||
shouldValidate: true,
|
shouldValidate: true,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<div className="proto-card-top">
|
<div className="proto-card-top">
|
||||||
<div className={`proto-icon pi-${card.protocol === "graphql" ? "gql" : card.protocol}`}>
|
<div className={`proto-icon pi-${card.protocol === "graphql" ? "gql" : card.protocol}`}>
|
||||||
{card.protocol === "graphql" ? "GQL" : card.protocol.toUpperCase()}
|
{card.protocol === "graphql" ? "GQL" : card.protocol.toUpperCase()}
|
||||||
|
</div>
|
||||||
|
<div className="proto-radio" />
|
||||||
</div>
|
</div>
|
||||||
<div className="proto-radio" />
|
<div className="proto-card-copy">
|
||||||
</div>
|
<h3>{card.title}</h3>
|
||||||
<div className="proto-card-copy">
|
<p>{card.description}</p>
|
||||||
<h3>{card.title}</h3>
|
</div>
|
||||||
<p>{card.description}</p>
|
</button>
|
||||||
</div>
|
);
|
||||||
</button>
|
})}
|
||||||
);
|
</div>
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="builder-card">
|
||||||
|
<header className="builder-card-header">
|
||||||
|
<div>
|
||||||
|
<h2>2 — Tool identity</h2>
|
||||||
|
<p>Name and description visible to the LLM at runtime.</p>
|
||||||
|
</div>
|
||||||
|
<span className="status-pill status-draft">draft</span>
|
||||||
|
</header>
|
||||||
|
<div className="builder-card-body">
|
||||||
|
<div className="form-grid">{commonFields.map(renderField)}</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="builder-card">
|
||||||
|
<header className="builder-card-header">
|
||||||
|
<div>
|
||||||
|
<h2>3 — Upstream target</h2>
|
||||||
|
<p>Protocol-specific target configuration exposed through one MCP tool.</p>
|
||||||
|
</div>
|
||||||
|
<span className={`protocol-pill protocol-${activeProtocol}`}>{activeProtocol}</span>
|
||||||
|
</header>
|
||||||
|
<div className="builder-card-body">
|
||||||
|
<div className="form-grid">
|
||||||
|
{protocolFields.map(renderField)}
|
||||||
|
{activeProtocol === "grpc" ? (
|
||||||
|
<label className="field-block field-block-wide">
|
||||||
|
<span>Descriptor set file</span>
|
||||||
|
<small className="field-hint">
|
||||||
|
Upload a compiled descriptor-set file to autofill the base64 payload.
|
||||||
|
</small>
|
||||||
|
<input
|
||||||
|
className="input"
|
||||||
|
type="file"
|
||||||
|
accept=".bin,.pb,.desc"
|
||||||
|
onChange={(event) => {
|
||||||
|
void handleDescriptorFileChange(event.target.files?.[0]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
) : null}
|
||||||
|
{activeProtocol === "rest"
|
||||||
|
? renderField({
|
||||||
|
name: "restStaticHeadersText",
|
||||||
|
label: "Static headers",
|
||||||
|
description:
|
||||||
|
"Always sent for this REST target before dynamic request headers are merged.",
|
||||||
|
rows: 8,
|
||||||
|
wide: true,
|
||||||
|
code: true,
|
||||||
|
})
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="info-banner">
|
||||||
|
<div className="info-dot" />
|
||||||
|
<p>
|
||||||
|
Headers and auth stay separate from path and payload mapping. Configure shared
|
||||||
|
transport headers in the execution section below.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="builder-card">
|
||||||
|
<header className="builder-card-header">
|
||||||
|
<div>
|
||||||
|
<h2>4 — Contract schemas</h2>
|
||||||
|
<p>Protocol-agnostic schemas for MCP input and output payloads.</p>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div className="builder-card-body">
|
||||||
|
<div className="form-grid">{schemaFields.map(renderField)}</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="builder-card">
|
||||||
|
<header className="builder-card-header">
|
||||||
|
<div>
|
||||||
|
<h2>5 — Mapping and execution</h2>
|
||||||
|
<p>
|
||||||
|
Translate MCP input to request fields, then map upstream output back to tool
|
||||||
|
output.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div className="builder-card-body">
|
||||||
|
<div className="section-divider">
|
||||||
|
<span className="section-divider-label">Input → Request</span>
|
||||||
|
<div className="section-divider-line" />
|
||||||
|
</div>
|
||||||
|
<div className="form-grid">{mappingFields.slice(0, 1).map(renderField)}</div>
|
||||||
|
|
||||||
|
<div className="section-divider">
|
||||||
|
<span className="section-divider-label">Response → Output</span>
|
||||||
|
<div className="section-divider-line" />
|
||||||
|
</div>
|
||||||
|
<div className="form-grid">{mappingFields.slice(1).map(renderField)}</div>
|
||||||
|
|
||||||
|
<div className="section-divider">
|
||||||
|
<span className="section-divider-label">Headers And Runtime</span>
|
||||||
|
<div className="section-divider-line" />
|
||||||
|
</div>
|
||||||
|
<div className="form-grid">{headerFields.map(renderField)}</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{creationMutation.error ? (
|
||||||
|
<div className="feedback-card feedback-error">
|
||||||
|
{creationMutation.error instanceof ApiError
|
||||||
|
? creationMutation.error.message
|
||||||
|
: "Failed to create operation"}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</form>
|
||||||
|
|
||||||
<section className="builder-card">
|
{actionBarContainer
|
||||||
<header className="builder-card-header">
|
? createPortal(
|
||||||
<div>
|
<div className="sticky-action-bar">
|
||||||
<h2>2 — Tool identity</h2>
|
<div className="sticky-action-copy">
|
||||||
<p>Name and description visible to the LLM at runtime.</p>
|
<span className="status-pill status-testing">ready to publish later</span>
|
||||||
</div>
|
<p>{protocolSummary(activeProtocol)}</p>
|
||||||
<span className="status-pill status-draft">draft</span>
|
</div>
|
||||||
</header>
|
<button
|
||||||
<div className="builder-card-body">
|
className="button-primary button-primary-strong"
|
||||||
<div className="form-grid">{commonFields.map(renderField)}</div>
|
type="submit"
|
||||||
</div>
|
form="operation-create-form"
|
||||||
</section>
|
disabled={creationMutation.isPending}
|
||||||
|
>
|
||||||
<section className="builder-card">
|
{creationMutation.isPending ? "Creating..." : "Create operation"}
|
||||||
<header className="builder-card-header">
|
</button>
|
||||||
<div>
|
</div>,
|
||||||
<h2>3 — Upstream target</h2>
|
actionBarContainer,
|
||||||
<p>Protocol-specific target configuration exposed through one MCP tool.</p>
|
)
|
||||||
</div>
|
: null}
|
||||||
<span className={`protocol-pill protocol-${activeProtocol}`}>{activeProtocol}</span>
|
</>
|
||||||
</header>
|
|
||||||
<div className="builder-card-body">
|
|
||||||
<div className="form-grid">
|
|
||||||
{protocolFields.map(renderField)}
|
|
||||||
{activeProtocol === "grpc" ? (
|
|
||||||
<label className="field-block field-block-wide">
|
|
||||||
<span>Descriptor set file</span>
|
|
||||||
<small className="field-hint">
|
|
||||||
Upload a compiled descriptor-set file to autofill the base64 payload.
|
|
||||||
</small>
|
|
||||||
<input
|
|
||||||
className="input"
|
|
||||||
type="file"
|
|
||||||
accept=".bin,.pb,.desc"
|
|
||||||
onChange={(event) => {
|
|
||||||
void handleDescriptorFileChange(event.target.files?.[0]);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
) : null}
|
|
||||||
{activeProtocol === "rest" ? renderField({
|
|
||||||
name: "restStaticHeadersText",
|
|
||||||
label: "Static headers",
|
|
||||||
description:
|
|
||||||
"Always sent for this REST target before dynamic request headers are merged.",
|
|
||||||
rows: 8,
|
|
||||||
wide: true,
|
|
||||||
code: true,
|
|
||||||
}) : null}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="info-banner">
|
|
||||||
<div className="info-dot" />
|
|
||||||
<p>
|
|
||||||
Headers and auth stay separate from path and payload mapping. Configure shared
|
|
||||||
transport headers in the execution section below.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className="builder-card">
|
|
||||||
<header className="builder-card-header">
|
|
||||||
<div>
|
|
||||||
<h2>4 — Contract schemas</h2>
|
|
||||||
<p>Protocol-agnostic schemas for MCP input and output payloads.</p>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<div className="builder-card-body">
|
|
||||||
<div className="form-grid">{schemaFields.map(renderField)}</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className="builder-card">
|
|
||||||
<header className="builder-card-header">
|
|
||||||
<div>
|
|
||||||
<h2>5 — Mapping and execution</h2>
|
|
||||||
<p>Translate MCP input to request fields, then map upstream output back to tool output.</p>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<div className="builder-card-body">
|
|
||||||
<div className="section-divider">
|
|
||||||
<span className="section-divider-label">Input → Request</span>
|
|
||||||
<div className="section-divider-line" />
|
|
||||||
</div>
|
|
||||||
<div className="form-grid">{mappingFields.slice(0, 1).map(renderField)}</div>
|
|
||||||
|
|
||||||
<div className="section-divider">
|
|
||||||
<span className="section-divider-label">Response → Output</span>
|
|
||||||
<div className="section-divider-line" />
|
|
||||||
</div>
|
|
||||||
<div className="form-grid">{mappingFields.slice(1).map(renderField)}</div>
|
|
||||||
|
|
||||||
<div className="section-divider">
|
|
||||||
<span className="section-divider-label">Headers And Runtime</span>
|
|
||||||
<div className="section-divider-line" />
|
|
||||||
</div>
|
|
||||||
<div className="form-grid">{headerFields.map(renderField)}</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{creationMutation.error ? (
|
|
||||||
<div className="feedback-card feedback-error">
|
|
||||||
{creationMutation.error instanceof ApiError
|
|
||||||
? creationMutation.error.message
|
|
||||||
: "Failed to create operation"}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
<div className="sticky-action-bar">
|
|
||||||
<div className="sticky-action-copy">
|
|
||||||
<span className="status-pill status-testing">ready to publish later</span>
|
|
||||||
<p>{protocolSummary(activeProtocol)}</p>
|
|
||||||
</div>
|
|
||||||
<button className="button-primary button-primary-strong" type="submit" disabled={creationMutation.isPending}>
|
|
||||||
{creationMutation.isPending ? "Creating..." : "Create operation"}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import { OperationForm } from "../../features/operation-form/operation-form";
|
import { OperationForm } from "../../features/operation-form/operation-form";
|
||||||
|
|
||||||
export function OperationCreatePage() {
|
export function OperationCreatePage() {
|
||||||
return (
|
return <OperationForm actionBarContainerId="app-layout-main" />;
|
||||||
<div className="page-stack">
|
|
||||||
<OperationForm />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export function AppShell({ children }: AppShellProps) {
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div className="logo-text">
|
<div className="logo-text">
|
||||||
<strong>MCPaaS</strong>
|
<strong>Crank</strong>
|
||||||
<span>Tool Console</span>
|
<span>Tool Console</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -60,6 +60,7 @@ export function AppShell({ children }: AppShellProps) {
|
|||||||
<p className="sidebar-label">Workspace</p>
|
<p className="sidebar-label">Workspace</p>
|
||||||
<nav className="sidebar-nav">
|
<nav className="sidebar-nav">
|
||||||
<NavLink
|
<NavLink
|
||||||
|
end
|
||||||
to="/operations"
|
to="/operations"
|
||||||
className={({ isActive }) =>
|
className={({ isActive }) =>
|
||||||
isActive ? "nav-link nav-link-active" : "nav-link"
|
isActive ? "nav-link nav-link-active" : "nav-link"
|
||||||
@@ -106,7 +107,7 @@ export function AppShell({ children }: AppShellProps) {
|
|||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<div className="layout-main">
|
<div className="layout-main" id="app-layout-main">
|
||||||
<header className="topbar">
|
<header className="topbar">
|
||||||
<div className="breadcrumb">
|
<div className="breadcrumb">
|
||||||
<span>{meta.section}</span>
|
<span>{meta.section}</span>
|
||||||
@@ -120,12 +121,14 @@ export function AppShell({ children }: AppShellProps) {
|
|||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main className="main-content">
|
<main className="main-content" id="app-main-content">
|
||||||
<div className="page-header">
|
<div className="main-content-inner">
|
||||||
<h1>{meta.heading}</h1>
|
<div className="page-header">
|
||||||
<p>{meta.subtitle}</p>
|
<h1>{meta.heading}</h1>
|
||||||
|
<p>{meta.subtitle}</p>
|
||||||
|
</div>
|
||||||
|
{children}
|
||||||
</div>
|
</div>
|
||||||
{children}
|
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+64
-5
@@ -316,12 +316,22 @@ button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.main-content {
|
.main-content {
|
||||||
padding: 28px;
|
width: 100%;
|
||||||
|
max-width: 1480px;
|
||||||
|
margin: 0 auto;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content-inner {
|
||||||
|
flex: 1;
|
||||||
|
padding: 28px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-header {
|
.page-header {
|
||||||
margin-bottom: 24px;
|
max-width: 1240px;
|
||||||
|
margin: 0 auto 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-header h1 {
|
.page-header h1 {
|
||||||
@@ -400,6 +410,18 @@ button {
|
|||||||
gap: 16px;
|
gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.builder-stack {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.builder-content {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 1240px;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: grid;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.page-section,
|
.page-section,
|
||||||
.builder-card,
|
.builder-card,
|
||||||
.operation-card,
|
.operation-card,
|
||||||
@@ -425,9 +447,16 @@ button {
|
|||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.builder-card-header {
|
||||||
|
padding: 20px 24px 0;
|
||||||
|
}
|
||||||
|
|
||||||
.section-header h2,
|
.section-header h2,
|
||||||
.builder-card-header h2 {
|
.builder-card-header h2 {
|
||||||
margin: 0 0 2px;
|
margin: 0 0 2px;
|
||||||
@@ -452,6 +481,12 @@ button {
|
|||||||
.builder-card-body {
|
.builder-card-body {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
|
padding: 0 24px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.builder-content .form-grid {
|
||||||
|
grid-template-columns: repeat(2, minmax(280px, 420px));
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.proto-grid {
|
.proto-grid {
|
||||||
@@ -843,8 +878,8 @@ button {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
padding: 12px 20px;
|
padding: 12px 28px;
|
||||||
border-radius: var(--radius-xl);
|
border-radius: 0;
|
||||||
background: rgba(255, 255, 255, 0.9);
|
background: rgba(255, 255, 255, 0.9);
|
||||||
backdrop-filter: blur(16px);
|
backdrop-filter: blur(16px);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
@@ -920,6 +955,7 @@ button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.field-inline {
|
.field-inline {
|
||||||
|
width: 100%;
|
||||||
max-width: 420px;
|
max-width: 420px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1093,9 +1129,17 @@ pre {
|
|||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-content {
|
.main-content-inner {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sticky-action-bar {
|
||||||
|
padding-inline: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.builder-content {
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 820px) {
|
@media (max-width: 820px) {
|
||||||
@@ -1116,4 +1160,19 @@ pre {
|
|||||||
.hero-metrics {
|
.hero-metrics {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.main-content-inner {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sticky-action-bar {
|
||||||
|
padding-inline: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.builder-card-header,
|
||||||
|
.builder-card-body,
|
||||||
|
.page-section {
|
||||||
|
padding-left: 16px;
|
||||||
|
padding-right: 16px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mcpaas-adapter-graphql"
|
name = "crank-adapter-graphql"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
mcpaas-core = { path = "../mcpaas-core" }
|
crank-core = { path = "../crank-core" }
|
||||||
mcpaas-mapping = { path = "../mcpaas-mapping" }
|
crank-mapping = { path = "../crank-mapping" }
|
||||||
reqwest.workspace = true
|
reqwest.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
+3
-3
@@ -1,7 +1,7 @@
|
|||||||
use std::{collections::BTreeMap, time::Duration};
|
use std::{collections::BTreeMap, time::Duration};
|
||||||
|
|
||||||
use mcpaas_core::GraphqlTarget;
|
use crank_core::GraphqlTarget;
|
||||||
use mcpaas_mapping::JsonPath;
|
use crank_mapping::JsonPath;
|
||||||
use reqwest::{
|
use reqwest::{
|
||||||
Client,
|
Client,
|
||||||
header::{CONTENT_TYPE, HeaderMap, HeaderName, HeaderValue},
|
header::{CONTENT_TYPE, HeaderMap, HeaderName, HeaderValue},
|
||||||
@@ -161,7 +161,7 @@ mod tests {
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use axum::{Json, Router, routing::post};
|
use axum::{Json, Router, routing::post};
|
||||||
use mcpaas_core::{GraphqlOperationType, GraphqlTarget};
|
use crank_core::{GraphqlOperationType, GraphqlTarget};
|
||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mcpaas-adapter-grpc"
|
name = "crank-adapter-grpc"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
@@ -10,8 +10,8 @@ test-support = []
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
base64.workspace = true
|
base64.workspace = true
|
||||||
mcpaas-core = { path = "../mcpaas-core" }
|
crank-core = { path = "../crank-core" }
|
||||||
mcpaas-proto = { path = "../mcpaas-proto" }
|
crank-proto = { path = "../crank-proto" }
|
||||||
prost.workspace = true
|
prost.workspace = true
|
||||||
prost-reflect.workspace = true
|
prost-reflect.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::{collections::BTreeMap, str::FromStr, time::Duration};
|
use std::{collections::BTreeMap, str::FromStr, time::Duration};
|
||||||
|
|
||||||
use base64::{Engine as _, engine::general_purpose::STANDARD};
|
use base64::{Engine as _, engine::general_purpose::STANDARD};
|
||||||
use mcpaas_core::GrpcTarget;
|
use crank_core::GrpcTarget;
|
||||||
use prost::Message;
|
use prost::Message;
|
||||||
use prost_reflect::{DescriptorPool, MethodDescriptor, prost_types::FileDescriptorSet};
|
use prost_reflect::{DescriptorPool, MethodDescriptor, prost_types::FileDescriptorSet};
|
||||||
use tonic::{
|
use tonic::{
|
||||||
@@ -138,7 +138,7 @@ fn normalize_headers(metadata: &tonic::metadata::MetadataMap) -> BTreeMap<String
|
|||||||
mod tests {
|
mod tests {
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use mcpaas_core::{DescriptorId, GrpcTarget};
|
use crank_core::{DescriptorId, GrpcTarget};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
use crate::{GrpcAdapter, GrpcRequest, test_support};
|
use crate::{GrpcAdapter, GrpcRequest, test_support};
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mcpaas-adapter-rest"
|
name = "crank-adapter-rest"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
mcpaas-core = { path = "../mcpaas-core" }
|
crank-core = { path = "../crank-core" }
|
||||||
reqwest.workspace = true
|
reqwest.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::{collections::BTreeMap, time::Duration};
|
use std::{collections::BTreeMap, time::Duration};
|
||||||
|
|
||||||
use mcpaas_core::{HttpMethod, RestTarget};
|
use crank_core::{HttpMethod, RestTarget};
|
||||||
use reqwest::{
|
use reqwest::{
|
||||||
Client,
|
Client,
|
||||||
header::{HeaderMap, HeaderName, HeaderValue},
|
header::{HeaderMap, HeaderName, HeaderValue},
|
||||||
@@ -174,7 +174,7 @@ mod tests {
|
|||||||
http::HeaderMap,
|
http::HeaderMap,
|
||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
};
|
};
|
||||||
use mcpaas_core::{HttpMethod, RestTarget};
|
use crank_core::{HttpMethod, RestTarget};
|
||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mcpaas-core"
|
name = "crank-core"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
@@ -321,7 +321,7 @@ mod tests {
|
|||||||
base_url: "https://api.example.com".to_owned(),
|
base_url: "https://api.example.com".to_owned(),
|
||||||
method: HttpMethod::Post,
|
method: HttpMethod::Post,
|
||||||
path_template: "/v1/leads".to_owned(),
|
path_template: "/v1/leads".to_owned(),
|
||||||
static_headers: BTreeMap::from([("X-App-Source".to_owned(), "mcpaas".to_owned())]),
|
static_headers: BTreeMap::from([("X-App-Source".to_owned(), "crank".to_owned())]),
|
||||||
}),
|
}),
|
||||||
input_schema: json!({"type":"object","fields":{"email":{"type":"string","required":true}}}),
|
input_schema: json!({"type":"object","fields":{"email":{"type":"string","required":true}}}),
|
||||||
output_schema: json!({"type":"object","fields":{"id":{"type":"string","required":true}}}),
|
output_schema: json!({"type":"object","fields":{"id":{"type":"string","required":true}}}),
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mcpaas-schema"
|
name = "crank-mapping"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
mcpaas-core = { path = "../mcpaas-core" }
|
crank-core = { path = "../crank-core" }
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mcpaas-proto"
|
name = "crank-proto"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
mcpaas-core = { path = "../mcpaas-core" }
|
crank-core = { path = "../crank-core" }
|
||||||
mcpaas-schema = { path = "../mcpaas-schema" }
|
crank-schema = { path = "../crank-schema" }
|
||||||
prost.workspace = true
|
prost.workspace = true
|
||||||
prost-reflect.workspace = true
|
prost-reflect.workspace = true
|
||||||
prost-types.workspace = true
|
prost-types.workspace = true
|
||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use mcpaas_schema::{Schema, SchemaKind};
|
use crank_schema::{Schema, SchemaKind};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::ProtoError,
|
errors::ProtoError,
|
||||||
@@ -161,7 +161,7 @@ fn scalar_schema(kind: &ProtoScalarKind) -> Schema {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use mcpaas_schema::SchemaKind;
|
use crank_schema::SchemaKind;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ProtoEnum, ProtoField, ProtoFieldCardinality, ProtoFieldType, ProtoMapField, ProtoMessage,
|
ProtoEnum, ProtoField, ProtoFieldCardinality, ProtoFieldType, ProtoMapField, ProtoMessage,
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mcpaas-registry"
|
name = "crank-registry"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
mcpaas-core = { path = "../mcpaas-core" }
|
crank-core = { path = "../crank-core" }
|
||||||
mcpaas-mapping = { path = "../mcpaas-mapping" }
|
crank-mapping = { path = "../crank-mapping" }
|
||||||
mcpaas-schema = { path = "../mcpaas-schema" }
|
crank-schema = { path = "../crank-schema" }
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
sqlx.workspace = true
|
sqlx.workspace = true
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
use mcpaas_core::{
|
use crank_core::{
|
||||||
AuthProfile, DescriptorId, ExportMode, Operation, OperationId, OperationStatus, Protocol,
|
AuthProfile, DescriptorId, ExportMode, Operation, OperationId, OperationStatus, Protocol,
|
||||||
SampleId,
|
SampleId,
|
||||||
};
|
};
|
||||||
use mcpaas_mapping::MappingSet;
|
use crank_mapping::MappingSet;
|
||||||
use mcpaas_schema::Schema;
|
use crank_schema::Schema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use mcpaas_core::{AuthProfile, OperationId, OperationStatus};
|
use crank_core::{AuthProfile, OperationId, OperationStatus};
|
||||||
use serde::{Serialize, de::DeserializeOwned};
|
use serde::{Serialize, de::DeserializeOwned};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use sqlx::{
|
use sqlx::{
|
||||||
@@ -481,7 +481,7 @@ impl PostgresRegistry {
|
|||||||
|
|
||||||
pub async fn get_auth_profile(
|
pub async fn get_auth_profile(
|
||||||
&self,
|
&self,
|
||||||
auth_profile_id: &mcpaas_core::AuthProfileId,
|
auth_profile_id: &crank_core::AuthProfileId,
|
||||||
) -> Result<Option<AuthProfile>, RegistryError> {
|
) -> Result<Option<AuthProfile>, RegistryError> {
|
||||||
let row = sqlx::query(
|
let row = sqlx::query(
|
||||||
"select
|
"select
|
||||||
@@ -917,7 +917,7 @@ fn map_operation_version_record(row: &PgRow) -> Result<OperationVersionRecord, R
|
|||||||
|
|
||||||
fn map_auth_profile(row: &PgRow) -> Result<AuthProfile, RegistryError> {
|
fn map_auth_profile(row: &PgRow) -> Result<AuthProfile, RegistryError> {
|
||||||
Ok(AuthProfile {
|
Ok(AuthProfile {
|
||||||
id: mcpaas_core::AuthProfileId::new(row.try_get::<String, _>("id")?),
|
id: crank_core::AuthProfileId::new(row.try_get::<String, _>("id")?),
|
||||||
name: row.try_get("name")?,
|
name: row.try_get("name")?,
|
||||||
kind: deserialize_enum_text(&row.try_get::<String, _>("kind")?, "kind")?,
|
kind: deserialize_enum_text(&row.try_get::<String, _>("kind")?, "kind")?,
|
||||||
config: deserialize_json_value(row.try_get::<Json<Value>, _>("config_json")?.0)?,
|
config: deserialize_json_value(row.try_get::<Json<Value>, _>("config_json")?.0)?,
|
||||||
@@ -928,7 +928,7 @@ fn map_auth_profile(row: &PgRow) -> Result<AuthProfile, RegistryError> {
|
|||||||
|
|
||||||
fn map_sample_metadata(row: &PgRow) -> Result<OperationSampleMetadata, RegistryError> {
|
fn map_sample_metadata(row: &PgRow) -> Result<OperationSampleMetadata, RegistryError> {
|
||||||
Ok(OperationSampleMetadata {
|
Ok(OperationSampleMetadata {
|
||||||
id: mcpaas_core::SampleId::new(row.try_get::<String, _>("id")?),
|
id: crank_core::SampleId::new(row.try_get::<String, _>("id")?),
|
||||||
operation_id: OperationId::new(row.try_get::<String, _>("operation_id")?),
|
operation_id: OperationId::new(row.try_get::<String, _>("operation_id")?),
|
||||||
version: from_db_version(row.try_get("version")?, "version")?,
|
version: from_db_version(row.try_get("version")?, "version")?,
|
||||||
sample_kind: deserialize_enum_text(
|
sample_kind: deserialize_enum_text(
|
||||||
@@ -944,7 +944,7 @@ fn map_sample_metadata(row: &PgRow) -> Result<OperationSampleMetadata, RegistryE
|
|||||||
|
|
||||||
fn map_descriptor_metadata(row: &PgRow) -> Result<DescriptorMetadata, RegistryError> {
|
fn map_descriptor_metadata(row: &PgRow) -> Result<DescriptorMetadata, RegistryError> {
|
||||||
Ok(DescriptorMetadata {
|
Ok(DescriptorMetadata {
|
||||||
id: mcpaas_core::DescriptorId::new(row.try_get::<String, _>("id")?),
|
id: crank_core::DescriptorId::new(row.try_get::<String, _>("id")?),
|
||||||
operation_id: row
|
operation_id: row
|
||||||
.try_get::<Option<String>, _>("operation_id")?
|
.try_get::<Option<String>, _>("operation_id")?
|
||||||
.map(OperationId::new),
|
.map(OperationId::new),
|
||||||
@@ -970,7 +970,7 @@ fn map_yaml_import_job(row: &PgRow) -> Result<YamlImportJob, RegistryError> {
|
|||||||
id: YamlImportJobId::new(row.try_get::<String, _>("id")?),
|
id: YamlImportJobId::new(row.try_get::<String, _>("id")?),
|
||||||
source_sample_id: row
|
source_sample_id: row
|
||||||
.try_get::<Option<String>, _>("source_sample_id")?
|
.try_get::<Option<String>, _>("source_sample_id")?
|
||||||
.map(mcpaas_core::SampleId::new),
|
.map(crank_core::SampleId::new),
|
||||||
status: deserialize_enum_text(&row.try_get::<String, _>("status")?, "status")?,
|
status: deserialize_enum_text(&row.try_get::<String, _>("status")?, "status")?,
|
||||||
format_version: row.try_get("format_version")?,
|
format_version: row.try_get("format_version")?,
|
||||||
mode: deserialize_enum_text(&row.try_get::<String, _>("mode")?, "mode")?,
|
mode: deserialize_enum_text(&row.try_get::<String, _>("mode")?, "mode")?,
|
||||||
@@ -1038,14 +1038,14 @@ mod tests {
|
|||||||
time::{SystemTime, UNIX_EPOCH},
|
time::{SystemTime, UNIX_EPOCH},
|
||||||
};
|
};
|
||||||
|
|
||||||
use mcpaas_core::{
|
use crank_core::{
|
||||||
ApiKeyHeaderAuthConfig, AuthConfig, AuthKind, AuthProfile, ConfigExport, ExecutionConfig,
|
ApiKeyHeaderAuthConfig, AuthConfig, AuthKind, AuthProfile, ConfigExport, ExecutionConfig,
|
||||||
ExportMode, GeneratedDraft, GeneratedDraftStatus, HttpMethod, OperationId, OperationStatus,
|
ExportMode, GeneratedDraft, GeneratedDraftStatus, HttpMethod, OperationId, OperationStatus,
|
||||||
Protocol, RestTarget, RetryPolicy, Samples, SecretRef, Target, ToolDescription,
|
Protocol, RestTarget, RetryPolicy, Samples, SecretRef, Target, ToolDescription,
|
||||||
ToolExample,
|
ToolExample,
|
||||||
};
|
};
|
||||||
use mcpaas_mapping::{MappingRule, MappingSet};
|
use crank_mapping::{MappingRule, MappingSet};
|
||||||
use mcpaas_schema::{Schema, SchemaKind};
|
use crank_schema::{Schema, SchemaKind};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use sqlx::{Executor, PgPool, postgres::PgPoolOptions};
|
use sqlx::{Executor, PgPool, postgres::PgPoolOptions};
|
||||||
|
|
||||||
@@ -1159,12 +1159,12 @@ mod tests {
|
|||||||
registry.create_operation(&operation, None).await.unwrap();
|
registry.create_operation(&operation, None).await.unwrap();
|
||||||
|
|
||||||
let auth_profile = AuthProfile {
|
let auth_profile = AuthProfile {
|
||||||
id: "auth_rmcp".into(),
|
id: "auth_crank".into(),
|
||||||
name: "RMCP API key".to_owned(),
|
name: "Crank API key".to_owned(),
|
||||||
kind: AuthKind::ApiKeyHeader,
|
kind: AuthKind::ApiKeyHeader,
|
||||||
config: AuthConfig::ApiKeyHeader(ApiKeyHeaderAuthConfig {
|
config: AuthConfig::ApiKeyHeader(ApiKeyHeaderAuthConfig {
|
||||||
header_name: "X-Api-Key".to_owned(),
|
header_name: "X-Api-Key".to_owned(),
|
||||||
secret_ref: SecretRef::new("vault://rmcp/api-key"),
|
secret_ref: SecretRef::new("vault://crank/api-key"),
|
||||||
}),
|
}),
|
||||||
created_at: "2026-03-25T12:00:00Z".to_owned(),
|
created_at: "2026-03-25T12:00:00Z".to_owned(),
|
||||||
updated_at: "2026-03-25T12:00:00Z".to_owned(),
|
updated_at: "2026-03-25T12:00:00Z".to_owned(),
|
||||||
@@ -1415,7 +1415,7 @@ mod tests {
|
|||||||
execution_config: ExecutionConfig {
|
execution_config: ExecutionConfig {
|
||||||
timeout_ms: 10_000,
|
timeout_ms: 10_000,
|
||||||
retry_policy: Some(RetryPolicy { max_attempts: 3 }),
|
retry_policy: Some(RetryPolicy { max_attempts: 3 }),
|
||||||
auth_profile_ref: Some("auth_rmcp".into()),
|
auth_profile_ref: Some("auth_crank".into()),
|
||||||
headers: BTreeMap::from([("X-Request-Id".to_owned(), "static".to_owned())]),
|
headers: BTreeMap::from([("X-Request-Id".to_owned(), "static".to_owned())]),
|
||||||
protocol_options: None,
|
protocol_options: None,
|
||||||
},
|
},
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
[package]
|
||||||
|
name = "crank-runtime"
|
||||||
|
edition.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
version.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
crank-adapter-graphql = { path = "../crank-adapter-graphql" }
|
||||||
|
crank-adapter-grpc = { path = "../crank-adapter-grpc" }
|
||||||
|
crank-adapter-rest = { path = "../crank-adapter-rest" }
|
||||||
|
crank-core = { path = "../crank-core" }
|
||||||
|
crank-mapping = { path = "../crank-mapping" }
|
||||||
|
crank-schema = { path = "../crank-schema" }
|
||||||
|
serde.workspace = true
|
||||||
|
serde_json.workspace = true
|
||||||
|
thiserror.workspace = true
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
axum.workspace = true
|
||||||
|
crank-adapter-grpc = { path = "../crank-adapter-grpc", features = ["test-support"] }
|
||||||
|
tokio.workspace = true
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
use mcpaas_adapter_graphql::GraphqlAdapterError;
|
use crank_adapter_graphql::GraphqlAdapterError;
|
||||||
use mcpaas_adapter_grpc::GrpcAdapterError;
|
use crank_adapter_grpc::GrpcAdapterError;
|
||||||
use mcpaas_adapter_rest::RestAdapterError;
|
use crank_adapter_rest::RestAdapterError;
|
||||||
use mcpaas_core::Protocol;
|
use crank_core::Protocol;
|
||||||
use mcpaas_mapping::MappingError;
|
use crank_mapping::MappingError;
|
||||||
use mcpaas_schema::SchemaError;
|
use crank_schema::SchemaError;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use mcpaas_adapter_graphql::{GraphqlAdapter, GraphqlRequest};
|
use crank_adapter_graphql::{GraphqlAdapter, GraphqlRequest};
|
||||||
use mcpaas_adapter_grpc::{GrpcAdapter, GrpcRequest};
|
use crank_adapter_grpc::{GrpcAdapter, GrpcRequest};
|
||||||
use mcpaas_adapter_rest::{RestAdapter, RestRequest};
|
use crank_adapter_rest::{RestAdapter, RestRequest};
|
||||||
use mcpaas_core::Target;
|
use crank_core::Target;
|
||||||
use serde_json::{Map, Value, json};
|
use serde_json::{Map, Value, json};
|
||||||
|
|
||||||
use crate::{AdapterResponse, PreparedRequest, RuntimeError, RuntimeOperation};
|
use crate::{AdapterResponse, PreparedRequest, RuntimeError, RuntimeOperation};
|
||||||
@@ -217,14 +217,14 @@ mod tests {
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use axum::{Json, Router, routing::post};
|
use axum::{Json, Router, routing::post};
|
||||||
use mcpaas_adapter_grpc::test_support as grpc_test_support;
|
use crank_adapter_grpc::test_support as grpc_test_support;
|
||||||
use mcpaas_core::{
|
use crank_core::{
|
||||||
DescriptorId, ExecutionConfig, GeneratedDraft, GeneratedDraftStatus, GraphqlOperationType,
|
DescriptorId, ExecutionConfig, GeneratedDraft, GeneratedDraftStatus, GraphqlOperationType,
|
||||||
GraphqlTarget, GrpcTarget, HttpMethod, Operation, OperationId, OperationStatus, Protocol,
|
GraphqlTarget, GrpcTarget, HttpMethod, Operation, OperationId, OperationStatus, Protocol,
|
||||||
RestTarget, Samples, Target, ToolDescription, ToolExample,
|
RestTarget, Samples, Target, ToolDescription, ToolExample,
|
||||||
};
|
};
|
||||||
use mcpaas_mapping::{MappingRule, MappingSet};
|
use crank_mapping::{MappingRule, MappingSet};
|
||||||
use mcpaas_schema::{Schema, SchemaKind};
|
use crank_schema::{Schema, SchemaKind};
|
||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use mcpaas_core::{ExecutionConfig, Operation, OperationId, Protocol, Target, ToolDescription};
|
use crank_core::{ExecutionConfig, Operation, OperationId, Protocol, Target, ToolDescription};
|
||||||
use mcpaas_mapping::MappingSet;
|
use crank_mapping::MappingSet;
|
||||||
use mcpaas_schema::Schema;
|
use crank_schema::Schema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mcpaas-mapping"
|
name = "crank-schema"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
mcpaas-core = { path = "../mcpaas-core" }
|
crank-core = { path = "../crank-core" }
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "mcpaas-runtime"
|
|
||||||
edition.workspace = true
|
|
||||||
license.workspace = true
|
|
||||||
rust-version.workspace = true
|
|
||||||
version.workspace = true
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
mcpaas-adapter-graphql = { path = "../mcpaas-adapter-graphql" }
|
|
||||||
mcpaas-adapter-grpc = { path = "../mcpaas-adapter-grpc" }
|
|
||||||
mcpaas-adapter-rest = { path = "../mcpaas-adapter-rest" }
|
|
||||||
mcpaas-core = { path = "../mcpaas-core" }
|
|
||||||
mcpaas-mapping = { path = "../mcpaas-mapping" }
|
|
||||||
mcpaas-schema = { path = "../mcpaas-schema" }
|
|
||||||
serde.workspace = true
|
|
||||||
serde_json.workspace = true
|
|
||||||
thiserror.workspace = true
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
axum.workspace = true
|
|
||||||
mcpaas-adapter-grpc = { path = "../mcpaas-adapter-grpc", features = ["test-support"] }
|
|
||||||
tokio.workspace = true
|
|
||||||
+19
-19
@@ -3,15 +3,15 @@ services:
|
|||||||
image: postgres:16-alpine
|
image: postgres:16-alpine
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_DB: ${POSTGRES_DB:-rmcp}
|
POSTGRES_DB: ${POSTGRES_DB:-crank}
|
||||||
POSTGRES_USER: ${POSTGRES_USER:-rmcp}
|
POSTGRES_USER: ${POSTGRES_USER:-crank}
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-rmcp}
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-crank}
|
||||||
volumes:
|
volumes:
|
||||||
- postgres_data:/var/lib/postgresql/data
|
- postgres_data:/var/lib/postgresql/data
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:5432:5432"
|
- "127.0.0.1:5432:5432"
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-rmcp} -d ${POSTGRES_DB:-rmcp}"]
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-crank} -d ${POSTGRES_DB:-crank}"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
retries: 5
|
||||||
@@ -22,18 +22,18 @@ services:
|
|||||||
dockerfile: apps/admin-api/Dockerfile
|
dockerfile: apps/admin-api/Dockerfile
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
MCPAAS_DATABASE_URL: ${MCPAAS_DATABASE_URL:-postgres://rmcp:rmcp@postgres:5432/rmcp}
|
CRANK_DATABASE_URL: ${CRANK_DATABASE_URL:-postgres://crank:crank@postgres:5432/crank}
|
||||||
MCPAAS_STORAGE_ROOT: ${MCPAAS_STORAGE_ROOT:-/var/lib/rmcp/storage}
|
CRANK_STORAGE_ROOT: ${CRANK_STORAGE_ROOT:-/var/lib/crank/storage}
|
||||||
MCPAAS_ADMIN_BIND: ${MCPAAS_ADMIN_BIND:-0.0.0.0:3001}
|
CRANK_ADMIN_BIND: ${CRANK_ADMIN_BIND:-0.0.0.0:3001}
|
||||||
MCPAAS_LOG_LEVEL: ${MCPAAS_LOG_LEVEL:-info}
|
CRANK_LOG_LEVEL: ${CRANK_LOG_LEVEL:-info}
|
||||||
MCPAAS_SECRET_PROVIDER: ${MCPAAS_SECRET_PROVIDER:-env}
|
CRANK_SECRET_PROVIDER: ${CRANK_SECRET_PROVIDER:-env}
|
||||||
depends_on:
|
depends_on:
|
||||||
postgres:
|
postgres:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
- artifact_storage:${MCPAAS_STORAGE_ROOT:-/var/lib/rmcp/storage}
|
- artifact_storage:${CRANK_STORAGE_ROOT:-/var/lib/crank/storage}
|
||||||
ports:
|
ports:
|
||||||
- "${MCPAAS_PUBLISH_HOST:-127.0.0.1}:3001:3001"
|
- "${CRANK_PUBLISH_HOST:-127.0.0.1}:3001:3001"
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "--fail", "http://127.0.0.1:3001/health"]
|
test: ["CMD", "curl", "--fail", "http://127.0.0.1:3001/health"]
|
||||||
interval: 15s
|
interval: 15s
|
||||||
@@ -46,18 +46,18 @@ services:
|
|||||||
dockerfile: apps/mcp-server/Dockerfile
|
dockerfile: apps/mcp-server/Dockerfile
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
MCPAAS_DATABASE_URL: ${MCPAAS_DATABASE_URL:-postgres://rmcp:rmcp@postgres:5432/rmcp}
|
CRANK_DATABASE_URL: ${CRANK_DATABASE_URL:-postgres://crank:crank@postgres:5432/crank}
|
||||||
MCPAAS_STORAGE_ROOT: ${MCPAAS_STORAGE_ROOT:-/var/lib/rmcp/storage}
|
CRANK_STORAGE_ROOT: ${CRANK_STORAGE_ROOT:-/var/lib/crank/storage}
|
||||||
MCPAAS_MCP_BIND: ${MCPAAS_MCP_BIND:-0.0.0.0:3002}
|
CRANK_MCP_BIND: ${CRANK_MCP_BIND:-0.0.0.0:3002}
|
||||||
MCPAAS_LOG_LEVEL: ${MCPAAS_LOG_LEVEL:-info}
|
CRANK_LOG_LEVEL: ${CRANK_LOG_LEVEL:-info}
|
||||||
MCPAAS_SECRET_PROVIDER: ${MCPAAS_SECRET_PROVIDER:-env}
|
CRANK_SECRET_PROVIDER: ${CRANK_SECRET_PROVIDER:-env}
|
||||||
depends_on:
|
depends_on:
|
||||||
postgres:
|
postgres:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
- artifact_storage:${MCPAAS_STORAGE_ROOT:-/var/lib/rmcp/storage}
|
- artifact_storage:${CRANK_STORAGE_ROOT:-/var/lib/crank/storage}
|
||||||
ports:
|
ports:
|
||||||
- "${MCPAAS_PUBLISH_HOST:-127.0.0.1}:3002:3002"
|
- "${CRANK_PUBLISH_HOST:-127.0.0.1}:3002:3002"
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "--fail", "http://127.0.0.1:3002/health"]
|
test: ["CMD", "curl", "--fail", "http://127.0.0.1:3002/health"]
|
||||||
interval: 15s
|
interval: 15s
|
||||||
@@ -70,7 +70,7 @@ services:
|
|||||||
dockerfile: apps/ui/Dockerfile
|
dockerfile: apps/ui/Dockerfile
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "${MCPAAS_PUBLISH_HOST:-127.0.0.1}:3000:3000"
|
- "${CRANK_PUBLISH_HOST:-127.0.0.1}:3000:3000"
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/"]
|
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/"]
|
||||||
interval: 15s
|
interval: 15s
|
||||||
|
|||||||
+22
-22
@@ -279,7 +279,7 @@ gRPC target:
|
|||||||
|
|
||||||
## 9. Основные компоненты
|
## 9. Основные компоненты
|
||||||
|
|
||||||
### `mcpaas-core`
|
### `crank-core`
|
||||||
|
|
||||||
Ответственность:
|
Ответственность:
|
||||||
|
|
||||||
@@ -288,7 +288,7 @@ gRPC target:
|
|||||||
- статусы и базовые protocol-specific target types,
|
- статусы и базовые protocol-specific target types,
|
||||||
- общие ошибки.
|
- общие ошибки.
|
||||||
|
|
||||||
### `mcpaas-schema`
|
### `crank-schema`
|
||||||
|
|
||||||
Ответственность:
|
Ответственность:
|
||||||
|
|
||||||
@@ -296,7 +296,7 @@ gRPC target:
|
|||||||
- представление типов и полей для UI и runtime,
|
- представление типов и полей для UI и runtime,
|
||||||
- валидация JSON относительно внутренней схемы.
|
- валидация JSON относительно внутренней схемы.
|
||||||
|
|
||||||
### `mcpaas-mapping`
|
### `crank-mapping`
|
||||||
|
|
||||||
Ответственность:
|
Ответственность:
|
||||||
|
|
||||||
@@ -305,7 +305,7 @@ gRPC target:
|
|||||||
- применение input/output mapping,
|
- применение input/output mapping,
|
||||||
- генерация чернового mapping по sample-данным и схемам.
|
- генерация чернового mapping по sample-данным и схемам.
|
||||||
|
|
||||||
### `mcpaas-proto`
|
### `crank-proto`
|
||||||
|
|
||||||
Ответственность:
|
Ответственность:
|
||||||
|
|
||||||
@@ -314,7 +314,7 @@ gRPC target:
|
|||||||
- извлечение services, methods и message schemas,
|
- извлечение services, methods и message schemas,
|
||||||
- преобразование protobuf metadata в нормализованные схемы.
|
- преобразование protobuf metadata в нормализованные схемы.
|
||||||
|
|
||||||
### `mcpaas-registry`
|
### `crank-registry`
|
||||||
|
|
||||||
Ответственность:
|
Ответственность:
|
||||||
|
|
||||||
@@ -323,7 +323,7 @@ gRPC target:
|
|||||||
- выдача списка активных tools,
|
- выдача списка активных tools,
|
||||||
- инвалидация кэша и сигналы на reload.
|
- инвалидация кэша и сигналы на reload.
|
||||||
|
|
||||||
### `mcpaas-runtime`
|
### `crank-runtime`
|
||||||
|
|
||||||
Ответственность:
|
Ответственность:
|
||||||
|
|
||||||
@@ -333,7 +333,7 @@ gRPC target:
|
|||||||
- применение output mapping,
|
- применение output mapping,
|
||||||
- единообразные runtime-ошибки.
|
- единообразные runtime-ошибки.
|
||||||
|
|
||||||
### `mcpaas-adapter-rest`
|
### `crank-adapter-rest`
|
||||||
|
|
||||||
Ответственность:
|
Ответственность:
|
||||||
|
|
||||||
@@ -341,7 +341,7 @@ gRPC target:
|
|||||||
- отправка запроса через `reqwest`,
|
- отправка запроса через `reqwest`,
|
||||||
- нормализация HTTP-ответа в JSON.
|
- нормализация HTTP-ответа в JSON.
|
||||||
|
|
||||||
### `mcpaas-adapter-graphql`
|
### `crank-adapter-graphql`
|
||||||
|
|
||||||
Ответственность:
|
Ответственность:
|
||||||
|
|
||||||
@@ -350,7 +350,7 @@ gRPC target:
|
|||||||
- отправка запроса,
|
- отправка запроса,
|
||||||
- извлечение `data` и ошибок из GraphQL-ответа.
|
- извлечение `data` и ошибок из GraphQL-ответа.
|
||||||
|
|
||||||
### `mcpaas-adapter-grpc`
|
### `crank-adapter-grpc`
|
||||||
|
|
||||||
Ответственность:
|
Ответственность:
|
||||||
|
|
||||||
@@ -358,7 +358,7 @@ gRPC target:
|
|||||||
- вызов unary RPC метода,
|
- вызов unary RPC метода,
|
||||||
- преобразование protobuf response обратно в нормализованный JSON.
|
- преобразование protobuf response обратно в нормализованный JSON.
|
||||||
|
|
||||||
### `mcpaas-admin-api`
|
### `crank-admin-api`
|
||||||
|
|
||||||
Ответственность:
|
Ответственность:
|
||||||
|
|
||||||
@@ -370,7 +370,7 @@ gRPC target:
|
|||||||
- endpoints для тестового выполнения операций,
|
- endpoints для тестового выполнения операций,
|
||||||
- discovery endpoints для gRPC metadata.
|
- discovery endpoints для gRPC metadata.
|
||||||
|
|
||||||
### `mcpaas-mcp-server`
|
### `crank-mcp-server`
|
||||||
|
|
||||||
Ответственность:
|
Ответственность:
|
||||||
|
|
||||||
@@ -379,7 +379,7 @@ gRPC target:
|
|||||||
- делегирование выполнения в runtime,
|
- делегирование выполнения в runtime,
|
||||||
- возврат нормализованного результата MCP-клиенту.
|
- возврат нормализованного результата MCP-клиенту.
|
||||||
|
|
||||||
### `mcpaas-ui`
|
### `crank-ui`
|
||||||
|
|
||||||
Ответственность:
|
Ответственность:
|
||||||
|
|
||||||
@@ -407,21 +407,21 @@ gRPC target:
|
|||||||
Для реализации рекомендуется workspace-структура:
|
Для реализации рекомендуется workspace-структура:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
mcpaas/
|
crank/
|
||||||
apps/
|
apps/
|
||||||
admin-api/
|
admin-api/
|
||||||
mcp-server/
|
mcp-server/
|
||||||
ui/
|
ui/
|
||||||
crates/
|
crates/
|
||||||
mcpaas-core/
|
crank-core/
|
||||||
mcpaas-schema/
|
crank-schema/
|
||||||
mcpaas-mapping/
|
crank-mapping/
|
||||||
mcpaas-proto/
|
crank-proto/
|
||||||
mcpaas-registry/
|
crank-registry/
|
||||||
mcpaas-runtime/
|
crank-runtime/
|
||||||
mcpaas-adapter-rest/
|
crank-adapter-rest/
|
||||||
mcpaas-adapter-graphql/
|
crank-adapter-graphql/
|
||||||
mcpaas-adapter-grpc/
|
crank-adapter-grpc/
|
||||||
docs/
|
docs/
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -169,7 +169,7 @@
|
|||||||
"method": "PATCH",
|
"method": "PATCH",
|
||||||
"path_template": "/v1/users/{userId}",
|
"path_template": "/v1/users/{userId}",
|
||||||
"static_headers": {
|
"static_headers": {
|
||||||
"X-App-Source": "mcpaas"
|
"X-App-Source": "crank"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -437,7 +437,7 @@
|
|||||||
},
|
},
|
||||||
"auth_profile_ref": "auth_01hr7x8rj2d8nq8v0c4m4t1r9e",
|
"auth_profile_ref": "auth_01hr7x8rj2d8nq8v0c4m4t1r9e",
|
||||||
"headers": {
|
"headers": {
|
||||||
"X-Client": "mcpaas"
|
"X-Client": "crank"
|
||||||
},
|
},
|
||||||
"protocol_options": {
|
"protocol_options": {
|
||||||
"rest": null,
|
"rest": null,
|
||||||
@@ -717,10 +717,10 @@ operation:
|
|||||||
|
|
||||||
Эта модель задает основу для:
|
Эта модель задает основу для:
|
||||||
|
|
||||||
- Rust structs в `mcpaas-core`, `mcpaas-schema`, `mcpaas-mapping`;
|
- Rust structs в `crank-core`, `crank-schema`, `crank-mapping`;
|
||||||
- DTO для `admin-api`;
|
- DTO для `admin-api`;
|
||||||
- таблиц `operations`, `operation_versions`, `operation_samples`, `operation_descriptors`;
|
- таблиц `operations`, `operation_versions`, `operation_samples`, `operation_descriptors`;
|
||||||
- import/export layer для `YAML` конфигураций;
|
- import/export layer для `YAML` конфигураций;
|
||||||
- runtime view, который будет передаваться в `mcpaas-runtime`.
|
- runtime view, который будет передаваться в `crank-runtime`.
|
||||||
|
|
||||||
Следующим логическим шагом после этого документа должна стать схема БД, в которой эти сущности будут разложены по таблицам и связям.
|
Следующим логическим шагом после этого документа должна стать схема БД, в которой эти сущности будут разложены по таблицам и связям.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## 1. Назначение документа
|
## 1. Назначение документа
|
||||||
|
|
||||||
Этот документ фиксирует структуру хранения конфигураций, версий операций, загруженных артефактов и published runtime-view. Его цель - дать основу для SQL-миграций и для реализации `mcpaas-registry`.
|
Этот документ фиксирует структуру хранения конфигураций, версий операций, загруженных артефактов и published runtime-view. Его цель - дать основу для SQL-миграций и для реализации `crank-registry`.
|
||||||
|
|
||||||
В документе предполагается реляционная модель, ориентированная на `PostgreSQL`. Канонической считается схема, совместимая с `PostgreSQL`.
|
В документе предполагается реляционная модель, ориентированная на `PostgreSQL`. Канонической считается схема, совместимая с `PostgreSQL`.
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
## 1. Цель документа
|
## 1. Цель документа
|
||||||
|
|
||||||
Этот документ фиксирует минимальный воспроизводимый сценарий запуска и демонстрации MCPaaS без знания внутренней структуры кода.
|
Этот документ фиксирует минимальный воспроизводимый сценарий запуска и демонстрации Crank без знания внутренней структуры кода.
|
||||||
|
|
||||||
## 2. Предусловия
|
## 2. Предусловия
|
||||||
|
|
||||||
- доступен `PostgreSQL`;
|
- доступен `PostgreSQL`;
|
||||||
- задан `MCPAAS_DATABASE_URL`;
|
- задан `CRANK_DATABASE_URL`;
|
||||||
- задан `MCPAAS_STORAGE_ROOT`;
|
- задан `CRANK_STORAGE_ROOT`;
|
||||||
- доступны `MCPAAS_ADMIN_BIND` и `MCPAAS_MCP_BIND`;
|
- доступны `CRANK_ADMIN_BIND` и `CRANK_MCP_BIND`;
|
||||||
- для UI установлен `Node.js`;
|
- для UI установлен `Node.js`;
|
||||||
- для Rust-части установлен toolchain из `rust-toolchain.toml`.
|
- для Rust-части установлен toolchain из `rust-toolchain.toml`.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -169,7 +169,7 @@ services:
|
|||||||
- не публиковать внутренние сервисы наружу без необходимости;
|
- не публиковать внутренние сервисы наружу без необходимости;
|
||||||
- содержать healthchecks.
|
- содержать healthchecks.
|
||||||
|
|
||||||
Практически это должно быть управляемо через env вроде `MCPAAS_PUBLISH_HOST`:
|
Практически это должно быть управляемо через env вроде `CRANK_PUBLISH_HOST`:
|
||||||
|
|
||||||
- `127.0.0.1` для local reverse proxy на том же Linux host;
|
- `127.0.0.1` для local reverse proxy на том же Linux host;
|
||||||
- конкретный внутренний IP или `0.0.0.0` для отдельного центрального reverse proxy в LAN.
|
- конкретный внутренний IP или `0.0.0.0` для отдельного центрального reverse proxy в LAN.
|
||||||
|
|||||||
@@ -55,10 +55,10 @@
|
|||||||
|
|
||||||
### 5.1. Что пишется через TDD обязательно
|
### 5.1. Что пишется через TDD обязательно
|
||||||
|
|
||||||
- `mcpaas-schema`
|
- `crank-schema`
|
||||||
- `mcpaas-mapping`
|
- `crank-mapping`
|
||||||
- `mcpaas-registry`
|
- `crank-registry`
|
||||||
- `mcpaas-runtime`
|
- `crank-runtime`
|
||||||
- YAML import/export
|
- YAML import/export
|
||||||
- versioning logic
|
- versioning logic
|
||||||
|
|
||||||
@@ -171,7 +171,7 @@
|
|||||||
Удаленный репозиторий проекта:
|
Удаленный репозиторий проекта:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
git@github.com:bsodfather/rmcp.git
|
git@github.com:bsodfather/crank.git
|
||||||
```
|
```
|
||||||
|
|
||||||
### 8.2. Ветки
|
### 8.2. Ветки
|
||||||
|
|||||||
+16
-16
@@ -15,15 +15,15 @@
|
|||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart LR
|
flowchart LR
|
||||||
UI[mcpaas-ui]
|
UI[crank-ui]
|
||||||
ADMIN[admin-api]
|
ADMIN[admin-api]
|
||||||
MCP[mcp-server]
|
MCP[mcp-server]
|
||||||
REG[mcpaas-registry]
|
REG[crank-registry]
|
||||||
RUN[mcpaas-runtime]
|
RUN[crank-runtime]
|
||||||
CORE[mcpaas-core]
|
CORE[crank-core]
|
||||||
SCHEMA[mcpaas-schema]
|
SCHEMA[crank-schema]
|
||||||
MAP[mcpaas-mapping]
|
MAP[crank-mapping]
|
||||||
PROTO[mcpaas-proto]
|
PROTO[crank-proto]
|
||||||
REST[adapter-rest]
|
REST[adapter-rest]
|
||||||
GQL[adapter-graphql]
|
GQL[adapter-graphql]
|
||||||
GRPC[adapter-grpc]
|
GRPC[adapter-grpc]
|
||||||
@@ -58,15 +58,15 @@ flowchart LR
|
|||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart TD
|
flowchart TD
|
||||||
CORE[mcpaas-core]
|
CORE[crank-core]
|
||||||
SCHEMA[mcpaas-schema]
|
SCHEMA[crank-schema]
|
||||||
MAP[mcpaas-mapping]
|
MAP[crank-mapping]
|
||||||
PROTO[mcpaas-proto]
|
PROTO[crank-proto]
|
||||||
REG[mcpaas-registry]
|
REG[crank-registry]
|
||||||
RUN[mcpaas-runtime]
|
RUN[crank-runtime]
|
||||||
REST[mcpaas-adapter-rest]
|
REST[crank-adapter-rest]
|
||||||
GQL[mcpaas-adapter-graphql]
|
GQL[crank-adapter-graphql]
|
||||||
GRPC[mcpaas-adapter-grpc]
|
GRPC[crank-adapter-grpc]
|
||||||
ADMIN[apps/admin-api]
|
ADMIN[apps/admin-api]
|
||||||
MCP[apps/mcp-server]
|
MCP[apps/mcp-server]
|
||||||
|
|
||||||
|
|||||||
+17
-17
@@ -25,15 +25,15 @@
|
|||||||
- `apps/admin-api`
|
- `apps/admin-api`
|
||||||
- `apps/mcp-server`
|
- `apps/mcp-server`
|
||||||
- `apps/ui`
|
- `apps/ui`
|
||||||
- `crates/mcpaas-core`
|
- `crates/crank-core`
|
||||||
- `crates/mcpaas-schema`
|
- `crates/crank-schema`
|
||||||
- `crates/mcpaas-mapping`
|
- `crates/crank-mapping`
|
||||||
- `crates/mcpaas-proto`
|
- `crates/crank-proto`
|
||||||
- `crates/mcpaas-registry`
|
- `crates/crank-registry`
|
||||||
- `crates/mcpaas-runtime`
|
- `crates/crank-runtime`
|
||||||
- `crates/mcpaas-adapter-rest`
|
- `crates/crank-adapter-rest`
|
||||||
- `crates/mcpaas-adapter-graphql`
|
- `crates/crank-adapter-graphql`
|
||||||
- `crates/mcpaas-adapter-grpc`
|
- `crates/crank-adapter-grpc`
|
||||||
|
|
||||||
Результат:
|
Результат:
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ DoD:
|
|||||||
|
|
||||||
Цель:
|
Цель:
|
||||||
|
|
||||||
- реализовать `mcpaas-schema`.
|
- реализовать `crank-schema`.
|
||||||
|
|
||||||
Фичи:
|
Фичи:
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ DoD:
|
|||||||
|
|
||||||
Цель:
|
Цель:
|
||||||
|
|
||||||
- реализовать `mcpaas-mapping`.
|
- реализовать `crank-mapping`.
|
||||||
|
|
||||||
Фичи:
|
Фичи:
|
||||||
|
|
||||||
@@ -139,7 +139,7 @@ DoD:
|
|||||||
|
|
||||||
Цель:
|
Цель:
|
||||||
|
|
||||||
- реализовать `mcpaas-registry` и миграции.
|
- реализовать `crank-registry` и миграции.
|
||||||
|
|
||||||
Фичи:
|
Фичи:
|
||||||
|
|
||||||
@@ -171,8 +171,8 @@ DoD:
|
|||||||
|
|
||||||
Фичи:
|
Фичи:
|
||||||
|
|
||||||
- `mcpaas-adapter-rest`
|
- `crank-adapter-rest`
|
||||||
- `mcpaas-runtime` для REST
|
- `crank-runtime` для REST
|
||||||
- REST test run
|
- REST test run
|
||||||
- создание REST operation
|
- создание REST operation
|
||||||
- publish REST operation
|
- publish REST operation
|
||||||
@@ -282,7 +282,7 @@ DoD:
|
|||||||
|
|
||||||
Фичи:
|
Фичи:
|
||||||
|
|
||||||
- `mcpaas-adapter-graphql`
|
- `crank-adapter-graphql`
|
||||||
- GraphQL target support;
|
- GraphQL target support;
|
||||||
- variables mapping;
|
- variables mapping;
|
||||||
- `response_path`;
|
- `response_path`;
|
||||||
@@ -309,11 +309,11 @@ DoD:
|
|||||||
|
|
||||||
Фичи:
|
Фичи:
|
||||||
|
|
||||||
- `mcpaas-proto`
|
- `crank-proto`
|
||||||
- descriptor loading;
|
- descriptor loading;
|
||||||
- service/method discovery;
|
- service/method discovery;
|
||||||
- protobuf normalization;
|
- protobuf normalization;
|
||||||
- `mcpaas-adapter-grpc`
|
- `crank-adapter-grpc`
|
||||||
- unary test runs;
|
- unary test runs;
|
||||||
- publish и вызов через MCP.
|
- publish и вызов через MCP.
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
Причина:
|
Причина:
|
||||||
|
|
||||||
- проект задуман как `MCPaaS`, а не как локальный single-process adapter;
|
- проект задуман как `Crank`, а не как локальный single-process adapter;
|
||||||
- нужен удаленный доступ к опубликованным tools;
|
- нужен удаленный доступ к опубликованным tools;
|
||||||
- published tools должны обновляться без пересборки и без локального обертывания каждого клиента.
|
- published tools должны обновляться без пересборки и без локального обертывания каждого клиента.
|
||||||
|
|
||||||
@@ -127,7 +127,7 @@ MVP-контракт `mcp-server` строится вокруг JSON-RPC мет
|
|||||||
1. MCP client вызывает tool.
|
1. MCP client вызывает tool.
|
||||||
2. `mcp-server` находит published runtime view.
|
2. `mcp-server` находит published runtime view.
|
||||||
3. Валидирует input относительно schema.
|
3. Валидирует input относительно schema.
|
||||||
4. Делегирует вызов в `mcpaas-runtime`.
|
4. Делегирует вызов в `crank-runtime`.
|
||||||
5. Возвращает результат.
|
5. Возвращает результат.
|
||||||
|
|
||||||
## 9. Обновление tools
|
## 9. Обновление tools
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## 1. Цель документа
|
## 1. Цель документа
|
||||||
|
|
||||||
Этот документ фиксирует детальную структуру проекта до начала активной разработки. Его задача - заранее ограничить ответственность каждого компонента, избежать разрастания `mcpaas-core`, не допустить появления "универсальных" структур на все случаи жизни и сохранить понятные границы между доменной логикой, runtime, адаптерами, API и UI.
|
Этот документ фиксирует детальную структуру проекта до начала активной разработки. Его задача - заранее ограничить ответственность каждого компонента, избежать разрастания `crank-core`, не допустить появления "универсальных" структур на все случаи жизни и сохранить понятные границы между доменной логикой, runtime, адаптерами, API и UI.
|
||||||
|
|
||||||
Основной принцип: каждый crate отвечает за один слой системы. Внутри crate модули должны быть маленькими, тематическими и с минимальным количеством публичных сущностей.
|
Основной принцип: каждый crate отвечает за один слой системы. Внутри crate модули должны быть маленькими, тематическими и с минимальным количеством публичных сущностей.
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
### 2.2. Что запрещено
|
### 2.2. Что запрещено
|
||||||
|
|
||||||
- помещать SQL, HTTP-клиенты или gRPC-клиенты в `mcpaas-core`;
|
- помещать SQL, HTTP-клиенты или gRPC-клиенты в `crank-core`;
|
||||||
- хранить в `core` "общие утилиты", не относящиеся к доменной модели;
|
- хранить в `core` "общие утилиты", не относящиеся к доменной модели;
|
||||||
- делать `runtime`, который напрямую читает БД;
|
- делать `runtime`, который напрямую читает БД;
|
||||||
- писать mapping-логику внутри REST, GraphQL или gRPC адаптеров;
|
- писать mapping-логику внутри REST, GraphQL или gRPC адаптеров;
|
||||||
@@ -41,28 +41,28 @@
|
|||||||
Рекомендуемая структура:
|
Рекомендуемая структура:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
mcpaas/
|
crank/
|
||||||
apps/
|
apps/
|
||||||
admin-api/
|
admin-api/
|
||||||
mcp-server/
|
mcp-server/
|
||||||
ui/
|
ui/
|
||||||
crates/
|
crates/
|
||||||
mcpaas-core/
|
crank-core/
|
||||||
mcpaas-registry/
|
crank-registry/
|
||||||
mcpaas-runtime/
|
crank-runtime/
|
||||||
mcpaas-adapter-rest/
|
crank-adapter-rest/
|
||||||
mcpaas-adapter-graphql/
|
crank-adapter-graphql/
|
||||||
mcpaas-adapter-grpc/
|
crank-adapter-grpc/
|
||||||
mcpaas-mapping/
|
crank-mapping/
|
||||||
mcpaas-schema/
|
crank-schema/
|
||||||
mcpaas-proto/
|
crank-proto/
|
||||||
```
|
```
|
||||||
|
|
||||||
Дополнительные crates `mcpaas-mapping`, `mcpaas-schema` и `mcpaas-proto` нужны затем, чтобы не перегружать `mcpaas-core`.
|
Дополнительные crates `crank-mapping`, `crank-schema` и `crank-proto` нужны затем, чтобы не перегружать `crank-core`.
|
||||||
|
|
||||||
## 4. Детальная декомпозиция по crate
|
## 4. Детальная декомпозиция по crate
|
||||||
|
|
||||||
### 4.1. `mcpaas-core`
|
### 4.1. `crank-core`
|
||||||
|
|
||||||
Назначение:
|
Назначение:
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ mcpaas/
|
|||||||
Что должно лежать в crate:
|
Что должно лежать в crate:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
mcpaas-core/
|
crank-core/
|
||||||
src/
|
src/
|
||||||
lib.rs
|
lib.rs
|
||||||
ids.rs
|
ids.rs
|
||||||
@@ -119,9 +119,9 @@ mcpaas-core/
|
|||||||
|
|
||||||
Причина:
|
Причина:
|
||||||
|
|
||||||
`mcpaas-core` должен быть максимально стабильным и независимым. Если положить туда все подряд, он станет точкой связности всей системы.
|
`crank-core` должен быть максимально стабильным и независимым. Если положить туда все подряд, он станет точкой связности всей системы.
|
||||||
|
|
||||||
### 4.2. `mcpaas-schema`
|
### 4.2. `crank-schema`
|
||||||
|
|
||||||
Назначение:
|
Назначение:
|
||||||
|
|
||||||
@@ -133,7 +133,7 @@ mcpaas-core/
|
|||||||
Структура:
|
Структура:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
mcpaas-schema/
|
crank-schema/
|
||||||
src/
|
src/
|
||||||
lib.rs
|
lib.rs
|
||||||
schema/
|
schema/
|
||||||
@@ -173,7 +173,7 @@ mcpaas-schema/
|
|||||||
|
|
||||||
Схемы будут использоваться почти везде, но это не повод тащить их в `core`. Иначе `core` станет тяжелым и начнет менять версию при каждом изменении схемной логики.
|
Схемы будут использоваться почти везде, но это не повод тащить их в `core`. Иначе `core` станет тяжелым и начнет менять версию при каждом изменении схемной логики.
|
||||||
|
|
||||||
### 4.3. `mcpaas-mapping`
|
### 4.3. `crank-mapping`
|
||||||
|
|
||||||
Назначение:
|
Назначение:
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ mcpaas-schema/
|
|||||||
Структура:
|
Структура:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
mcpaas-mapping/
|
crank-mapping/
|
||||||
src/
|
src/
|
||||||
lib.rs
|
lib.rs
|
||||||
model/
|
model/
|
||||||
@@ -229,7 +229,7 @@ mcpaas-mapping/
|
|||||||
|
|
||||||
не помещать mapping-правила в строковые поля, которые потом интерпретируются каждым адаптером по-своему. Mapping должен быть единым движком.
|
не помещать mapping-правила в строковые поля, которые потом интерпретируются каждым адаптером по-своему. Mapping должен быть единым движком.
|
||||||
|
|
||||||
### 4.4. `mcpaas-proto`
|
### 4.4. `crank-proto`
|
||||||
|
|
||||||
Назначение:
|
Назначение:
|
||||||
|
|
||||||
@@ -240,7 +240,7 @@ mcpaas-mapping/
|
|||||||
Структура:
|
Структура:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
mcpaas-proto/
|
crank-proto/
|
||||||
src/
|
src/
|
||||||
lib.rs
|
lib.rs
|
||||||
descriptor/
|
descriptor/
|
||||||
@@ -272,14 +272,14 @@ mcpaas-proto/
|
|||||||
- `descriptor/registry.rs` - индексирование описаний для поиска services/methods.
|
- `descriptor/registry.rs` - индексирование описаний для поиска services/methods.
|
||||||
- `reflect/client.rs` - клиент server reflection, если будет добавлен.
|
- `reflect/client.rs` - клиент server reflection, если будет добавлен.
|
||||||
- `model/*` - protobuf-ориентированная промежуточная модель.
|
- `model/*` - protobuf-ориентированная промежуточная модель.
|
||||||
- `convert/to_schema.rs` - перевод protobuf message в `mcpaas-schema`.
|
- `convert/to_schema.rs` - перевод protobuf message в `crank-schema`.
|
||||||
- `convert/to_json.rs` и `from_json.rs` - преобразование runtime payload.
|
- `convert/to_json.rs` и `from_json.rs` - преобразование runtime payload.
|
||||||
|
|
||||||
Почему отдельный crate:
|
Почему отдельный crate:
|
||||||
|
|
||||||
protobuf-логика объемная и быстро начнет загрязнять gRPC adapter, если не отделить ее сразу.
|
protobuf-логика объемная и быстро начнет загрязнять gRPC adapter, если не отделить ее сразу.
|
||||||
|
|
||||||
### 4.5. `mcpaas-registry`
|
### 4.5. `crank-registry`
|
||||||
|
|
||||||
Назначение:
|
Назначение:
|
||||||
|
|
||||||
@@ -290,7 +290,7 @@ protobuf-логика объемная и быстро начнет загряз
|
|||||||
Структура:
|
Структура:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
mcpaas-registry/
|
crank-registry/
|
||||||
src/
|
src/
|
||||||
lib.rs
|
lib.rs
|
||||||
model/
|
model/
|
||||||
@@ -332,7 +332,7 @@ mcpaas-registry/
|
|||||||
|
|
||||||
`registry` не выполняет операции и не знает о `reqwest`/`tonic`. Он только хранит и отдает согласованные представления.
|
`registry` не выполняет операции и не знает о `reqwest`/`tonic`. Он только хранит и отдает согласованные представления.
|
||||||
|
|
||||||
### 4.6. `mcpaas-runtime`
|
### 4.6. `crank-runtime`
|
||||||
|
|
||||||
Назначение:
|
Назначение:
|
||||||
|
|
||||||
@@ -343,7 +343,7 @@ mcpaas-registry/
|
|||||||
Структура:
|
Структура:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
mcpaas-runtime/
|
crank-runtime/
|
||||||
src/
|
src/
|
||||||
lib.rs
|
lib.rs
|
||||||
executor/
|
executor/
|
||||||
@@ -380,7 +380,7 @@ mcpaas-runtime/
|
|||||||
|
|
||||||
`runtime` не должен знать, где хранится операция. Он получает уже готовую `runtime_operation`.
|
`runtime` не должен знать, где хранится операция. Он получает уже готовую `runtime_operation`.
|
||||||
|
|
||||||
### 4.7. `mcpaas-adapter-rest`
|
### 4.7. `crank-adapter-rest`
|
||||||
|
|
||||||
Назначение:
|
Назначение:
|
||||||
|
|
||||||
@@ -389,7 +389,7 @@ mcpaas-runtime/
|
|||||||
Структура:
|
Структура:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
mcpaas-adapter-rest/
|
crank-adapter-rest/
|
||||||
src/
|
src/
|
||||||
lib.rs
|
lib.rs
|
||||||
client.rs
|
client.rs
|
||||||
@@ -411,7 +411,7 @@ mcpaas-adapter-rest/
|
|||||||
|
|
||||||
REST adapter не валидирует MCP input и не знает о registry. Он получает уже подготовленный request contract.
|
REST adapter не валидирует MCP input и не знает о registry. Он получает уже подготовленный request contract.
|
||||||
|
|
||||||
### 4.8. `mcpaas-adapter-graphql`
|
### 4.8. `crank-adapter-graphql`
|
||||||
|
|
||||||
Назначение:
|
Назначение:
|
||||||
|
|
||||||
@@ -420,7 +420,7 @@ REST adapter не валидирует MCP input и не знает о registry.
|
|||||||
Структура:
|
Структура:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
mcpaas-adapter-graphql/
|
crank-adapter-graphql/
|
||||||
src/
|
src/
|
||||||
lib.rs
|
lib.rs
|
||||||
client.rs
|
client.rs
|
||||||
@@ -443,7 +443,7 @@ GraphQL adapter не занимается introspection по умолчанию
|
|||||||
|
|
||||||
один GraphQL tool соответствует одному заранее определенному `query` или `mutation`. Адаптер не должен принимать от LLM произвольный GraphQL-документ, потому что в MCP-модели операция должна оставаться узкой, предсказуемой и валидируемой по фиксированной схеме.
|
один GraphQL tool соответствует одному заранее определенному `query` или `mutation`. Адаптер не должен принимать от LLM произвольный GraphQL-документ, потому что в MCP-модели операция должна оставаться узкой, предсказуемой и валидируемой по фиксированной схеме.
|
||||||
|
|
||||||
### 4.9. `mcpaas-adapter-grpc`
|
### 4.9. `crank-adapter-grpc`
|
||||||
|
|
||||||
Назначение:
|
Назначение:
|
||||||
|
|
||||||
@@ -452,7 +452,7 @@ GraphQL adapter не занимается introspection по умолчанию
|
|||||||
Структура:
|
Структура:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
mcpaas-adapter-grpc/
|
crank-adapter-grpc/
|
||||||
src/
|
src/
|
||||||
lib.rs
|
lib.rs
|
||||||
channel.rs
|
channel.rs
|
||||||
@@ -470,7 +470,7 @@ mcpaas-adapter-grpc/
|
|||||||
|
|
||||||
Правило:
|
Правило:
|
||||||
|
|
||||||
gRPC adapter не должен сам парсить `.proto`. Этим занимается `mcpaas-proto`. Иначе в адаптере смешаются discovery и execution.
|
gRPC adapter не должен сам парсить `.proto`. Этим занимается `crank-proto`. Иначе в адаптере смешаются discovery и execution.
|
||||||
|
|
||||||
Дополнительное ограничение:
|
Дополнительное ограничение:
|
||||||
|
|
||||||
@@ -609,22 +609,22 @@ UI должен декомпозироваться по пользователь
|
|||||||
Целевой граф зависимостей:
|
Целевой граф зависимостей:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
mcpaas-core
|
crank-core
|
||||||
mcpaas-schema -> mcpaas-core
|
crank-schema -> crank-core
|
||||||
mcpaas-mapping -> mcpaas-core
|
crank-mapping -> crank-core
|
||||||
mcpaas-proto -> mcpaas-core, mcpaas-schema
|
crank-proto -> crank-core, crank-schema
|
||||||
mcpaas-registry -> mcpaas-core, mcpaas-schema, mcpaas-mapping
|
crank-registry -> crank-core, crank-schema, crank-mapping
|
||||||
mcpaas-adapter-rest -> mcpaas-core
|
crank-adapter-rest -> crank-core
|
||||||
mcpaas-adapter-graphql -> mcpaas-core
|
crank-adapter-graphql -> crank-core
|
||||||
mcpaas-adapter-grpc -> mcpaas-core, mcpaas-proto
|
crank-adapter-grpc -> crank-core, crank-proto
|
||||||
mcpaas-runtime -> mcpaas-core, mcpaas-schema, mcpaas-mapping, adapters
|
crank-runtime -> crank-core, crank-schema, crank-mapping, adapters
|
||||||
admin-api -> mcpaas-core, mcpaas-schema, mcpaas-mapping, mcpaas-proto, mcpaas-registry, mcpaas-runtime
|
admin-api -> crank-core, crank-schema, crank-mapping, crank-proto, crank-registry, crank-runtime
|
||||||
mcp-server -> mcpaas-core, mcpaas-registry, mcpaas-runtime
|
mcp-server -> crank-core, crank-registry, crank-runtime
|
||||||
```
|
```
|
||||||
|
|
||||||
Критические ограничения:
|
Критические ограничения:
|
||||||
|
|
||||||
- `mcpaas-core` ни от кого не зависит;
|
- `crank-core` ни от кого не зависит;
|
||||||
- адаптеры не зависят от `registry`;
|
- адаптеры не зависят от `registry`;
|
||||||
- `runtime` не зависит от `admin-api` и `mcp-server`;
|
- `runtime` не зависит от `admin-api` и `mcp-server`;
|
||||||
- `registry` не зависит от адаптеров;
|
- `registry` не зависит от адаптеров;
|
||||||
@@ -675,17 +675,17 @@ mcp-server -> mcpaas-core, mcpaas-registry, mcpaas-runtime
|
|||||||
|
|
||||||
Рекомендуемый порядок разработки:
|
Рекомендуемый порядок разработки:
|
||||||
|
|
||||||
1. `mcpaas-core`
|
1. `crank-core`
|
||||||
2. `mcpaas-schema`
|
2. `crank-schema`
|
||||||
3. `mcpaas-mapping`
|
3. `crank-mapping`
|
||||||
4. `mcpaas-registry`
|
4. `crank-registry`
|
||||||
5. `mcpaas-adapter-rest`
|
5. `crank-adapter-rest`
|
||||||
6. `mcpaas-runtime`
|
6. `crank-runtime`
|
||||||
7. `admin-api`
|
7. `admin-api`
|
||||||
8. `ui`
|
8. `ui`
|
||||||
9. `mcpaas-proto`
|
9. `crank-proto`
|
||||||
10. `mcpaas-adapter-grpc`
|
10. `crank-adapter-grpc`
|
||||||
11. `mcpaas-adapter-graphql`
|
11. `crank-adapter-graphql`
|
||||||
12. `mcp-server`
|
12. `mcp-server`
|
||||||
|
|
||||||
Причина такого порядка:
|
Причина такого порядка:
|
||||||
@@ -699,7 +699,7 @@ mcp-server -> mcpaas-core, mcpaas-registry, mcpaas-runtime
|
|||||||
|
|
||||||
Если придерживаться этой декомпозиции, то:
|
Если придерживаться этой декомпозиции, то:
|
||||||
|
|
||||||
- `mcpaas-core` останется маленьким и стабильным;
|
- `crank-core` останется маленьким и стабильным;
|
||||||
- schema и mapping не смешаются с transport-логикой;
|
- schema и mapping не смешаются с transport-логикой;
|
||||||
- protobuf discovery не загрязнит gRPC runtime;
|
- protobuf discovery не загрязнит gRPC runtime;
|
||||||
- `admin-api` и `mcp-server` останутся тонкими входными слоями;
|
- `admin-api` и `mcp-server` останутся тонкими входными слоями;
|
||||||
|
|||||||
+13
-13
@@ -28,7 +28,7 @@
|
|||||||
Рекомендуемая структура:
|
Рекомендуемая структура:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
var/mcpaas/
|
var/crank/
|
||||||
samples/
|
samples/
|
||||||
descriptors/
|
descriptors/
|
||||||
yaml-imports/
|
yaml-imports/
|
||||||
@@ -57,24 +57,24 @@ var/mcpaas/
|
|||||||
|
|
||||||
Минимально ожидаются:
|
Минимально ожидаются:
|
||||||
|
|
||||||
- `MCPAAS_DATABASE_URL`
|
- `CRANK_DATABASE_URL`
|
||||||
- `MCPAAS_STORAGE_ROOT`
|
- `CRANK_STORAGE_ROOT`
|
||||||
- `MCPAAS_ADMIN_BIND`
|
- `CRANK_ADMIN_BIND`
|
||||||
- `MCPAAS_MCP_BIND`
|
- `CRANK_MCP_BIND`
|
||||||
- `MCPAAS_MCP_REFRESH_MS`
|
- `CRANK_MCP_REFRESH_MS`
|
||||||
- `MCPAAS_LOG_LEVEL`
|
- `CRANK_LOG_LEVEL`
|
||||||
- `MCPAAS_SECRET_PROVIDER`
|
- `CRANK_SECRET_PROVIDER`
|
||||||
- `MCPAAS_PUBLIC_BASE_URL`
|
- `CRANK_PUBLIC_BASE_URL`
|
||||||
- `MCPAAS_MCP_PUBLIC_URL`
|
- `CRANK_MCP_PUBLIC_URL`
|
||||||
|
|
||||||
Опционально:
|
Опционально:
|
||||||
|
|
||||||
- `MCPAAS_ADMIN_TOKEN`
|
- `CRANK_ADMIN_TOKEN`
|
||||||
- `MCPAAS_MASTER_KEY`
|
- `CRANK_MASTER_KEY`
|
||||||
|
|
||||||
Стартовое значение для refresh published tools:
|
Стартовое значение для refresh published tools:
|
||||||
|
|
||||||
- `MCPAAS_MCP_REFRESH_MS=5000`
|
- `CRANK_MCP_REFRESH_MS=5000`
|
||||||
|
|
||||||
## 6. Логирование и трассировка
|
## 6. Логирование и трассировка
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user