Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
eaa8ceb
Make local cargo builds reproducible
Jul 15, 2026
bd1e4dc
Add FastMCP TrailBase sidecar
Jul 15, 2026
60527ea
Document local build dependency bootstrap
Jul 15, 2026
92a1f2b
Fix MCP admin CSRF handling
Jul 15, 2026
143bcc0
Support TrailBase config updates in MCP
Jul 15, 2026
2516543
Add MCP schema modes and file uploads
Jul 15, 2026
bab7cfb
Document TrailBase and MCP endpoint URLs
Jul 15, 2026
578769b
Document Record API query parameters for MCP
Jul 15, 2026
8b4a05b
Add generic TrailBase endpoint MCP tool
Jul 15, 2026
ebc3a23
Expand MCP Docker Hub README
Jul 15, 2026
0f8dedd
Use published MCP Docker image in docs
Jul 15, 2026
f3baaf5
Support token files for MCP credentials
Jul 15, 2026
7a5a1b7
Document MCP token lifetime checks
Jul 15, 2026
7ca558a
Prefer Portainer token environment variable
Jul 15, 2026
1f145d4
Support login credentials for MCP auth
Jul 15, 2026
168635e
Add TrailBase OpenAPI operation catalog
Jul 15, 2026
fefa6da
Prepare MCP 0.2 Docker release
Jul 15, 2026
6235a81
Document Record API table constraints
Jul 15, 2026
0ec3e72
Clarify Portainer credential options
Jul 15, 2026
beb571e
Merge remote-tracking branch 'origin/main' into trailbase-mcp
Aug 9, 2026
81c3f5c
Add native MCP server to TrailBase
Aug 9, 2026
1b7c1d4
Add OAuth login flow for native MCP
Aug 9, 2026
601f80b
Replace MCP sidecar with native deployment
Aug 9, 2026
1610ef2
Add native MCP schema and config tools
Aug 9, 2026
b2c7e93
Bind OAuth tokens to the MCP resource
Aug 9, 2026
246f75a
Scope MCP authentication to the MCP route
Aug 9, 2026
69bcb58
Clarify portable MCP client configuration
Aug 9, 2026
eaa6ea9
Use localhost in MCP quick start
Aug 9, 2026
2c27a1f
Use depot flag in MCP deployment examples
Aug 9, 2026
286111a
Explain native MCP deployment arguments
Aug 9, 2026
5bf2123
Add local and public MCP client examples
Aug 9, 2026
9401046
Explain MCP connection naming
Aug 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,8 @@

[env]
TS_RS_EXPORT_DIR = { value = "./crates/assets/js/bindings", relative = true }
LIBCLANG_PATH = { value = "./.dev-tools/libclang-18/usr/lib/llvm-18/lib", relative = true }
CLANG_PATH = { value = "./.dev-tools/libclang-18/usr/bin/clang-18", relative = true }
PKG_CONFIG_PATH = { value = "./.dev-tools/geos/usr/lib/x86_64-linux-gnu/pkgconfig", relative = true }
PKG_CONFIG_SYSROOT_DIR = { value = "./.dev-tools/geos", relative = true }
PROTOC = { value = "./.cargo/protoc-wrapper.sh", relative = true }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to assume that his is an artifact

11 changes: 11 additions & 0 deletions .cargo/protoc-wrapper.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env sh
set -eu

SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
REPO_ROOT=$(CDPATH= cd -- "${SCRIPT_DIR}/.." && pwd)
PROTOBUF_DIR="${REPO_ROOT}/.dev-tools/protobuf"

export LD_LIBRARY_PATH="${PROTOBUF_DIR}/usr/lib/x86_64-linux-gnu${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
exec "${PROTOBUF_DIR}/usr/bin/protoc" \
-I"${PROTOBUF_DIR}/usr/include" \
"$@"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above?

5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
target/
node_modules/
dist/
.dev-tools/
.venv*/
.python-*/
__pycache__/
.pytest_cache/

# Dart workspace artifacts
.dart_tool
Expand Down
99 changes: 99 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ minijinja = { version = "2.1.2", default-features = false }
parking_lot = { version = "0.12.3", default-features = false, features = ["send_guard", "arc_lock"] }
rand = "^0.10.0"
reqwest = { version = "0.13.1", default-features = false, features = ["rustls", "json"] }
rmcp = { version = "3.1.2", features = ["transport-streamable-http-server"] }
rusqlite = { version = "0.40.0", default-features = false, features = ["bundled", "cache", "column_decltype", "functions", "backup", "preupdate_hook"] }
rust-embed = { version = "8.4.0", default-features = false, features = ["mime-guess"] }
serde = { version = "^1.0.203", features = ["derive", "rc"] }
Expand Down
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,20 @@ trail components add trailbase/auth_ui
endpoints, e.g.
[http://localhost:4000/\_/auth/login](http://localhost:4000/_/auth/login).

## MCP

This fork includes an optional native MCP server in the main TrailBase binary.
It uses TrailBase administrator login through OAuth and runs on the same port as
TrailBase—no sidecar container or copied bearer token is required.

```sh
trail --public-url https://trailbase.example.com run --mcp
```

Connect an OAuth-capable MCP client to
`https://trailbase.example.com/mcp`. See the [MCP guide](mcp/README.md) for IDE,
Docker, Portainer, reverse-proxy, authentication, and security configuration.

## Building

If you have all the necessary build dependencies (Rust, node.js, geos,
Expand All @@ -162,6 +176,15 @@ pnpm install
cargo build --bin trail
```

On Debian/Ubuntu-style systems without sudo access to install build packages,
this fork can populate the repo-local `.dev-tools/` cache used by
`.cargo/config.toml`:

```sh
scripts/bootstrap-local-dev-tools.sh
cargo check --workspace --all-targets
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, so the above files are not artifacts.

This is a bit surprising since, I would expect most devs to have access to their machines (seems like a reasonable requirement). Otherwise, this is also very deb centric. If you don't have full access, wouldn't one rather develop inside a container? Would love to hear more about the reasoning.


Alternatively, if you want to build a Docker image or don't want to deal with
build dependencies, you can simply run:

Expand Down
4 changes: 4 additions & 0 deletions crates/cli/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ pub struct ServerArgs {
#[arg(long)]
pub demo: bool,

/// Enable the authenticated MCP endpoint at /mcp on the admin server.
#[arg(long, env, default_value_t = false)]
pub mcp: bool,

#[arg(long, default_value_t = false)]
pub stderr_logging: bool,

Expand Down
1 change: 1 addition & 0 deletions crates/cli/src/bin/trail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ async fn async_main(
tls_key: None,
tls_cert: None,
custom_router: None,
enable_mcp: cmd.mcp,
},
)
.await?;
Expand Down
1 change: 1 addition & 0 deletions crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ quick_cache = "0.7.0"
rand = { workspace = true }
regex = "1.11.0"
reqwest = { workspace = true }
rmcp = { workspace = true }
rusqlite = { workspace = true }
rust-embed = { workspace = true }
serde = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion crates/core/src/auth/api/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ pub(crate) async fn build_auth_token_flow_response(
///
/// An example using the two-step "authentication code flow" with PKCE can be found in
/// `/examples/blog/flutter`.
async fn build_authorization_code_flow_and_pkce_response(
pub(crate) async fn build_authorization_code_flow_and_pkce_response(
state: &AppState,
db_user: &DbUser,
redirect: String,
Expand Down
6 changes: 3 additions & 3 deletions crates/core/src/auth/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ pub(super) mod change_email;
pub(super) mod change_password;
pub(super) mod change_username;
pub(super) mod delete;
pub(super) mod login;
pub(crate) mod login;
pub(super) mod login_anonymous;
pub(super) mod logout;
pub(super) mod otp;
pub(super) mod promote_anonymous;
pub(super) mod refresh;
pub(crate) mod refresh;
pub(super) mod register;
pub(super) mod reset_password;
pub(super) mod status;
pub(super) mod token;
pub(crate) mod token;
pub(super) mod totp;
pub(super) mod verify_email;
11 changes: 11 additions & 0 deletions crates/core/src/auth/jwt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,17 @@ impl JwtHelper {
.map(|data| data.claims);
}

pub(crate) fn decode_with_audience<T: DeserializeOwned + Clone>(
&self,
token: &str,
audience: &str,
) -> Result<T, JwtError> {
let mut validation = self.validation.clone();
validation.set_audience(&[audience]);
return jsonwebtoken::decode::<T>(token, &self.decoding_key, &validation)
.map(|data| data.claims);
}

pub fn encode<T: Serialize>(&self, claims: &T) -> Result<String, JwtError> {
return jsonwebtoken::encode::<T>(&self.header, claims, &self.encoding_key);
}
Expand Down
1 change: 1 addition & 0 deletions crates/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ mod encryption;
mod extract;
mod init_error;
mod listing;
mod mcp;
mod migrations;
mod scheduler;
mod schema_metadata;
Expand Down
Loading