# PulseEngine MCP Macros
Procedural macros for the PulseEngine MCP Framework that dramatically simplify server and tool development.
## Quick Start
Add to your `Cargo.toml`:
```toml
[dependencies]
# Core macros
pulseengine-mcp-macros = "0.7.1"
# Required dependencies for generated code
pulseengine-mcp-protocol = "0.7.1"
pulseengine-mcp-server = "0.7.1"
pulseengine-mcp-transport = "0.7.1"
async-trait = "0.1"
thiserror = "1.0"
tokio = { version = "1.0", features = ["full"] }
# For STDIO transport (recommended)
tracing = "0.1"
tracing-subscriber = "0.3"
```
## Basic Server Example
```rust
use pulseengine_mcp_macros::{mcp_server, mcp_tools};
#[mcp_server(name = "Hello Server")]
#[derive(Default, Clone)]
pub struct HelloServer;
#[mcp_tools]
impl HelloServer {
/// Say hello to someone
pub async fn hello(&self, name: Option<String>) -> anyhow::Result<String> {
Ok(format!("Hello, {}!", name.unwrap_or_else(|| "World".to_string())))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// CRITICAL for STDIO: Configure logging to stderr
HelloServer::configure_stdio_logging();
let server = HelloServer::with_defaults().serve_stdio().await?;
server.run().await?;
Ok(())
}
```
## Required Dependencies
### Always Required
These dependencies are **always required** when using `#[mcp_server]`:
```toml
pulseengine-mcp-protocol = "0.7.1"
pulseengine-mcp-server = "0.7.1"
pulseengine-mcp-transport = "0.7.1"
async-trait = "0.1"
thiserror = "1.0"
tokio = { version = "1.0", features = ["full"] }
```
### Feature-Based Dependencies
#### STDIO Logging (`stdio-logging` feature)
For STDIO transport compatibility:
```toml
pulseengine-mcp-macros = { version = "0.7.1", features = ["stdio-logging"] }
tracing-subscriber = "0.3"
```
#### Authentication (`auth` feature + auth parameter)
**Important**: Authentication is **opt-in**. By default, servers have no authentication.
When using `auth = "memory"`, `auth = "file"`, etc.:
```toml
pulseengine-mcp-macros = { version = "0.7.1", features = ["auth"] }
pulseengine-mcp-auth = "0.7.1"
```
## Macros
### `#[mcp_server]`
Generates a complete MCP server from a struct:
```rust
#[mcp_server(
name = "My Server",
version = "1.0.0",
description = "Server description",
auth = "memory" // Optional: "memory", "file", "disabled"
)]
#[derive(Default, Clone)]
pub struct MyServer;
```
**Generated methods:**
- `MyServer::with_defaults()` - Create instance
- `MyServer::serve_stdio()` - Start STDIO transport
- `MyServer::serve_http(port)` - Start HTTP transport
- `MyServer::configure_stdio_logging()` - Fix STDIO logging
### `#[mcp_tools]`
Automatically discovers public methods as MCP tools:
```rust
#[mcp_tools]
impl MyServer {
/// Tool description from doc comment
pub async fn my_tool(&self, param: String) -> anyhow::Result<String> {
Ok(format!("Result: {}", param))
}
}
```
**Note**: Currently passthrough - full implementation coming soon.
## Transport Types
### STDIO (Default)
For MCP clients like Claude Desktop:
```rust
// CRITICAL: Configure logging first!
MyServer::configure_stdio_logging();
let server = MyServer::with_defaults().serve_stdio().await?;
```
### HTTP
For web-based clients:
```rust
let server = MyServer::with_defaults().serve_http(8080).await?;
```
### WebSocket
For real-time clients:
```rust
let server = MyServer::with_defaults().serve_websocket(8080).await?;
```
## Authentication
**By default, servers have no authentication**. To enable authentication, add the `auth` parameter:
```rust
// Memory-based (development)
#[mcp_server(name = "Dev Server", auth = "memory")]
// File-based (production)
#[mcp_server(name = "Prod Server", auth = "file", app_name = "my-app")]
// Explicitly disabled (same as default)
#[mcp_server(name = "Test Server", auth = "disabled")]
// No auth parameter = no authentication (default)
#[mcp_server(name = "Simple Server")]
```
**Requires**: `pulseengine-mcp-auth` dependency and `auth` feature only when `auth` parameter is specified.
## STDIO Transport Critical Note
⚠️ **CRITICAL**: For STDIO transport, you **MUST** configure logging to go to stderr, not stdout. Stdout is reserved for JSON-RPC messages only.
```rust
// Always call this before serve_stdio()
MyServer::configure_stdio_logging();
```
Failure to do this will break MCP client compatibility with errors like:
```
Error from MCP server: SyntaxError: Unexpected token '2025-0"... is not valid JSON
```
## Complete Example
See [`examples/hello-world-stdio-fixed/`](../examples/hello-world-stdio-fixed/) for a working example with proper STDIO logging configuration.
## License
Licensed under either of
- Apache License, Version 2.0, ([LICENSE-APACHE](../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.