Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
237 changes: 213 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,56 +43,245 @@ DC_API_KEY="service:docontrol-api:your-apollo-key"
Create a YAML configuration file (e.g., `config.yaml`):

```yaml
# GraphQL endpoint
endpoint: "https://apollo-gateway-v4-api.prod.docontrol.io/graphql"
# GraphQL endpoint URL
endpoint: https://apollo-gateway-v4-api.prod.docontrol.io/graphql

# Transport configuration (stdio for MCP)
transport:
type: stdio

# Apollo GraphOS configuration
# Authentication headers (automatically managed by token refresh)
headers:
Authorization: Bearer <token-will-be-auto-refreshed>

# Apollo GraphOS integration
graphos:
apollo_key: "${DC_API_KEY}" # From environment variable
apollo-graph-ref: docontrol-api@current
apollo-key: service:docontrol-api:your-apollo-key

# Use introspection to discover operations
operations: introspect
# Mutation mode: "none" (read-only), "all" (full access)
allow-mutations: none

# Enable introspection
# Operation source: use introspection to discover operations
operations:
- introspect

# Logging configuration
logging:
level: error
format: plain
color: false

# Introspection tools configuration
introspection:
query: true
mutation: true
execute:
enabled: true # Enable execute tool to run queries
introspect:
enabled: true # Enable introspect tool for schema discovery
minify: true # Minify schema output
search:
enabled: true # Enable search tool for finding types
minify: true # Minify search results
index_memory_bytes: 50000000 # Memory limit for search index
leaf_depth: 1 # Depth for leaf type expansion
validate:
enabled: true # Enable validate tool for query validation
```

**Note**: The `apollo_graph_ref` is hardcoded in the source code as `docontrol-api@current`. You can override it by setting the `DC_GRAPH_REF` environment variable if needed.
#### Configuration Options Explained

**Core Settings:**
- `endpoint`: The DoControl GraphQL API endpoint
- `transport.type`: `stdio` for MCP communication (required for MCP clients)

**Authentication:**
- `headers.Authorization`: Automatically updated by token refresh system
- The token in this section is managed by the server - it will be overwritten on startup and during refresh

**GraphOS Integration:**
- `apollo-graph-ref`: Your graph reference in Apollo Studio (e.g., `docontrol-api@current`)
- `apollo-key`: Your Apollo Studio API key for schema registry access

**Security:**
- `allow-mutations`: Set to `none` for read-only access, `all` to allow mutations

**Operations:**
- `introspect`: Use introspection to discover all queries and mutations automatically
- Alternative: `uplink` to use Apollo Studio operation collections

**Introspection Tools:**
The server provides 4 MCP tools when introspection is enabled:

1. **`execute`**: Run GraphQL queries and mutations
- Validates operation syntax
- Executes against the live endpoint
- Returns JSON results

2. **`introspect`**: Explore the GraphQL schema
- Get type information with hierarchy
- Discover fields, arguments, and descriptions
- Navigate relationships between types

**Note**: The `auth` section in the config file is automatically managed by the token refresh system. You don't need to manually specify it.
3. **`search`**: Find types in the schema by name
- Fuzzy search across all types
- Returns matching type definitions
- Useful for discovery

**Introspection Mode**: The server will introspect the GraphQL schema and automatically expose all queries and mutations as MCP tools. No need to manually define operations!
4. **`validate`**: Validate GraphQL operations before execution
- Syntax checking
- Schema validation
- Helpful for debugging

## MCP Client Configuration
**Note**: The `apollo_key` can reference environment variables using `${DC_API_KEY}` syntax.
Copy link

Choose a reason for hiding this comment

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

Should apollo_key be apollo-key to match the configuration examples above? The config uses hyphens but this note uses underscores.

Suggested change
**Note**: The `apollo_key` can reference environment variables using `${DC_API_KEY}` syntax.
**Note**: The `apollo-key` can reference environment variables using `${DC_API_KEY}` syntax.

Finding type: Naming and Typos


### Cursor/Claude Desktop
**Note**: The `Authorization` header is automatically managed by the token refresh system. You don't need to manually update it.

Add this to your MCP configuration file:
- **Cursor**: `~/.cursor/mcp.json`
- **Claude Desktop**: `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
## Quick Start Setup Guide

### Step 1: Install the Server

**Option A: Download from Releases**
```bash
# macOS (Apple Silicon)
curl -L https://github.com/docontrol-io/dc-mcp-server/releases/latest/download/dc-mcp-server-macos-aarch64.tar.gz | tar xz
chmod +x dc-mcp-server

# Linux
curl -L https://github.com/docontrol-io/dc-mcp-server/releases/latest/download/dc-mcp-server-linux-x86_64.tar.gz | tar xz
chmod +x dc-mcp-server

# Move to a permanent location
sudo mv dc-mcp-server /usr/local/bin/
```

**Option B: Build from Source**
```bash
git clone https://github.com/docontrol-io/dc-mcp-server.git
cd dc-mcp-server
cargo build --release
sudo cp target/release/dc-mcp-server /usr/local/bin/
```

### Step 2: Create Configuration File

Create a file named `docontrol-config.yaml`:

```yaml
endpoint: https://apollo-gateway-v4-api.prod.docontrol.io/graphql
transport:
type: stdio
headers:
Authorization: Bearer placeholder # Will be auto-updated
graphos:
apollo-graph-ref: docontrol-api@current
apollo-key: service:docontrol-api:YOUR_APOLLO_KEY_HERE
allow-mutations: none
operations:
- introspect
logging:
level: error
format: plain
color: false
introspection:
execute:
enabled: true
introspect:
enabled: true
minify: true
search:
enabled: true
minify: true
validate:
enabled: true
```

**Replace `YOUR_APOLLO_KEY_HERE`** with your actual Apollo Studio API key.

### Step 3: Get Your Credentials

You'll need two secrets from DoControl:

1. **Refresh Token** (`DC_REFRESH_TOKEN`):
- Obtain from DoControl OAuth authentication flow
- This is a long-lived token used to get fresh access tokens
- Keep this secret secure!

2. **Apollo API Key** (`DC_API_KEY`):
- Format: `service:docontrol-api:xxxxx`
- Used to access Apollo Studio for schema registry

### Step 4: Configure Your MCP Client

**For Cursor:**

Edit `~/.cursor/mcp.json`:

```json
{
"mcpServers": {
"docontrol": {
"command": "/path/to/dc-mcp-server",
"args": ["/path/to/config.yaml"],
"dc-mcp-server": {
"command": "/usr/local/bin/dc-mcp-server",
"args": ["/absolute/path/to/docontrol-config.yaml"],
"env": {
"DC_TOKEN_REFRESH_ENABLED": "true",
"DC_REFRESH_TOKEN": "your-refresh-token",
"DC_REFRESH_TOKEN": "YOUR_REFRESH_TOKEN_HERE",
"DC_REFRESH_URL": "https://auth.prod.docontrol.io/refresh",
"DC_GRAPHQL_ENDPOINT": "https://apollo-gateway-v4-api.prod.docontrol.io/graphql",
"DC_GRAPH_REF": "docontrol-api@current",
"DC_API_KEY": "service:docontrol-api:your-key",
"RUST_LOG": "info"
"DC_API_KEY": "service:docontrol-api:YOUR_KEY_HERE",
"RUST_LOG": "info",
"RUSTLS_SYSTEM_CERT_ROOT": "1"
}
}
}
}
```

**For Claude Desktop (macOS):**

Edit `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
"mcpServers": {
"dc-mcp-server": {
"command": "/usr/local/bin/dc-mcp-server",
"args": ["/absolute/path/to/docontrol-config.yaml"],
"env": {
"DC_TOKEN_REFRESH_ENABLED": "true",
"DC_REFRESH_TOKEN": "YOUR_REFRESH_TOKEN_HERE",
"DC_REFRESH_URL": "https://auth.prod.docontrol.io/refresh",
"DC_GRAPHQL_ENDPOINT": "https://apollo-gateway-v4-api.prod.docontrol.io/graphql",
"DC_API_KEY": "service:docontrol-api:YOUR_KEY_HERE",
"RUST_LOG": "info",
"RUSTLS_SYSTEM_CERT_ROOT": "1"
}
}
}
}
```

**Important Notes:**
- Use **absolute paths** for both the command and config file
- Replace `YOUR_REFRESH_TOKEN_HERE` and `YOUR_KEY_HERE` with actual values
- The `RUSTLS_SYSTEM_CERT_ROOT=1` is required for SSL certificate validation

### Step 5: Restart Your MCP Client

- **Cursor**: Restart the application or reload the window
- **Claude Desktop**: Quit and restart the application

### Step 6: Verify Setup

In your MCP client, you should see 4 new tools available:
- ✅ `execute` - Run GraphQL queries
- ✅ `introspect` - Explore the schema
- ✅ `search` - Search for types
- ✅ `validate` - Validate queries

Try asking: "What is the company information?" or "Show me the company details"

## MCP Client Configuration Reference

### Using with MCP Inspector

For testing and debugging:
Expand Down
1 change: 1 addition & 0 deletions crates/dc-mcp-server/src/graphql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ pub trait Executable {
let response = client
.post(request.endpoint.as_str())
.headers(self.headers(&request.headers))
.header("Content-Type", "application/json")
.body(Value::Object(request_body).to_string())
.send()
.await
Expand Down
19 changes: 14 additions & 5 deletions crates/dc-mcp-server/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::path::PathBuf;
use std::sync::Arc;

use apollo_mcp_registry::platform_api::operation_collections::collection_poller::CollectionSource;
use apollo_mcp_registry::uplink::persisted_queries::ManifestSource;
Expand All @@ -12,6 +13,7 @@ use dc_mcp_server::operations::OperationSource;
use dc_mcp_server::server::Server;
use dc_mcp_server::startup;
use runtime::IdOrDefault;
use tokio::sync::RwLock;
use tracing::{info, warn};

mod runtime;
Expand Down Expand Up @@ -41,7 +43,7 @@ async fn main() -> anyhow::Result<()> {
let config_path = args.config.clone();

// Read config for initial setup (telemetry)
let mut config: runtime::Config = match config_path.clone() {
let config: runtime::Config = match config_path.clone() {
Some(ref path) => runtime::read_config(path.clone())?,
None => runtime::read_config_from_env().unwrap_or_default(),
};
Expand All @@ -53,6 +55,9 @@ async fn main() -> anyhow::Result<()> {
env!("CARGO_PKG_VERSION")
);

// Create shared headers that can be updated by token refresh
let shared_headers = Arc::new(RwLock::new(config.headers.clone()));

// Check if token refresh is enabled
if startup::is_token_refresh_enabled() {
if let (Some(refresh_token), Some(refresh_url), Some(graphql_endpoint), Some(config_file)) = (
Expand All @@ -67,14 +72,14 @@ async fn main() -> anyhow::Result<()> {
refresh_token,
refresh_url,
graphql_endpoint,
Arc::clone(&shared_headers),
)
.await
{
warn!("Token refresh initialization failed: {}", e);
} else {
// Re-read config to get the refreshed token
info!("Re-reading config file to load refreshed token...");
config = runtime::read_config(config_file.clone())?;
// Token has been refreshed and shared_headers updated by initialize_with_token_refresh
info!("✅ Token refresh initialization complete");
}
} else {
warn!("Token refresh enabled but missing required environment variables");
Expand Down Expand Up @@ -141,13 +146,17 @@ async fn main() -> anyhow::Result<()> {

let transport = config.transport.clone();

// Read current headers from shared state
let current_headers = shared_headers.read().await.clone();

Ok(Server::builder()
.transport(config.transport)
.schema_source(schema_source)
.operation_source(operation_source)
.endpoint(config.endpoint.into_inner())
.maybe_explorer_graph_ref(explorer_graph_ref)
.headers(config.headers)
.headers(current_headers)
.maybe_shared_headers(Some(shared_headers))
.execute_introspection(config.introspection.execute.enabled)
.validate_introspection(config.introspection.validate.enabled)
.introspect_introspection(config.introspection.introspect.enabled)
Expand Down
5 changes: 5 additions & 0 deletions crates/dc-mcp-server/src/server.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use std::net::{IpAddr, Ipv4Addr};
use std::sync::Arc;

use apollo_mcp_registry::uplink::schema::SchemaSource;
use bon::bon;
use reqwest::header::{CONTENT_TYPE, HeaderMap, HeaderValue};
use schemars::JsonSchema;
use serde::Deserialize;
use tokio::sync::RwLock;
use url::Url;

use crate::auth;
Expand All @@ -26,6 +28,7 @@ pub struct Server {
operation_source: OperationSource,
endpoint: Url,
headers: HeaderMap,
shared_headers: Option<Arc<RwLock<HeaderMap>>>,
execute_introspection: bool,
validate_introspection: bool,
introspect_introspection: bool,
Expand Down Expand Up @@ -111,6 +114,7 @@ impl Server {
operation_source: OperationSource,
endpoint: Url,
headers: HeaderMap,
#[builder(into)] shared_headers: Option<Arc<RwLock<HeaderMap>>>,
execute_introspection: bool,
validate_introspection: bool,
introspect_introspection: bool,
Expand Down Expand Up @@ -139,6 +143,7 @@ impl Server {
operation_source,
endpoint,
headers,
shared_headers,
execute_introspection,
validate_introspection,
introspect_introspection,
Expand Down
Loading