#
tokens: 5152/50000 6/6 files
lines: off (toggle) GitHub
raw markdown copy
# Directory Structure

```
├── .gitignore
├── package.json
├── readme.md
├── showSettings.js
├── src
│   └── index.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
node_modules
build
package-lock.json
yarn.lock
```

--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------

```markdown
# MCP Server Guide

To build the MCP server, run:

```
npm install && npm run build
```

This will compile the typescript files and produce a build directory plus it will output the json you can copy/paste into your MCP client (Claude Desktop, Windsurf, Cursor, etc.)

If all things go well, this will produce an output similar to this:

```json
{
  "mcpServers": {
    "doordash": {
      "command": "node",
      "args": [
        "<thePathToYour>/build/index.js"
      ],
      "env": [
        {
          "DOORDASH_API_KEY": "<REPLACE>"
        }
      ]
    }
  }
}
```

## Support & Feedback
If things do not compile, or you have more advanced needs, please reach out to me at, [email protected].

## Sharing

If you have found value in this service please share it on social media. You can tag me [@jordandalton](https://x.com/jordankdalton) on X, or [jdcarnivore](https://www.reddit.com/user/jdcarnivore) on Reddit.
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "outDir": "./build",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "allowSyntheticDefaultImports": true,
    "moduleDetection": "force",
    "allowJs": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "doordash-mcp-server",
  "version": "1.0.0",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "build": "tsc && chmod 755 build/index.js && node showSettings"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.8.0",
    "axios": "^1.8.4",
    "jsonwebtoken": "^9.0.2",
    "zod": "^3.24.2"
  },
  "devDependencies": {
    "@types/node": "^22.14.0",
    "typescript": "^5.8.3"
  }
}

```

--------------------------------------------------------------------------------
/showSettings.js:
--------------------------------------------------------------------------------

```javascript
import path from 'path';
import fs from 'fs';

const filePath = path.join(process.cwd(), 'build', 'index.js');

// look for any env variables inside the file
const env = {};

// Read the file
const fileContent = fs.readFileSync(filePath, 'utf-8');

// Find all env variables
const envRegex = /process\.env\.(\w+)/g;
let match;
while ((match = envRegex.exec(fileContent)) !== null) {
    const row = { [match[1]]: '<REPLACE>' };
    Object.assign(env, row);
}

const structure = {
    mcpServers : {
        "doordash" : {
            command : "node",
            args : [filePath],
            env : env
        }
    }
}

console.log('Copy/Paste into your MCP client:');
console.log(
    JSON.stringify(structure, null, 2)
);

```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import axios from 'axios';
import jwt from "jsonwebtoken";

const developer_id = process.env.DOORDASH_DEVELOPER_ID;
const key_id = process.env.DOORDASH_KEY_ID;
const signing_secret = process.env.DOORDASH_SIGNING_SECRET;

// Create an MCP server
const server = new McpServer({
  name: "DoorDashDriveAPI",
  version: "1.0.0"
});

const issuedAt = Math.floor(Date.now() / 1000);
  const expirationDuration = 300;

  const jwtData = {
    aud: 'doordash',
    iss: developer_id,
    kid: key_id,
    exp: issuedAt + expirationDuration,
    iat: issuedAt,
  }
  
  const token = jwt.sign(
    jwtData,
    Buffer.from(signing_secret, 'base64'),
    {
      algorithm: "HS256",
      header: {
        alg: "HS256",
        'dd-ver': 'DD-JWT-V1'
      }
    } as unknown as jwt.SignOptions
  );

// Helper function to make API requests with authentication
async function makeApiRequest(url: string, method: string, data?: any) {
  const headers = {
    Authorization: `Bearer ${token}`,
    'Content-Type': 'application/json',
  };
  try {
    const response = await axios({
      url: url,
      method: method,
      data: data,
      headers
    });
    return response.data;
  } catch (error) {
    console.error("API request failed:", error);
    throw error; // Re-throw the error for the tool to handle
  }
}

// Tool: Create Quote
server.tool("create_quote",
  {
    external_delivery_id: z.string(),
    locale: z.string().optional(),
    order_fulfillment_method: z.string().optional(),
    origin_facility_id: z.string().optional(),
    pickup_address: z.string().optional(),
    pickup_business_name: z.string().optional(),
    pickup_phone_number: z.string().optional(),
    pickup_instructions: z.string().optional(),
    pickup_reference_tag: z.string().optional(),
    pickup_external_business_id: z.string().optional(),
    pickup_external_store_id: z.string().optional(),
    pickup_verification_metadata: z.record(z.any()).optional(),
    dropoff_address: z.string(),
    dropoff_business_name: z.string().optional(),
    dropoff_location: z.record(z.any()).optional(),
    dropoff_phone_number: z.string(),
    dropoff_instructions: z.string().optional(),
    dropoff_contact_given_name: z.string().optional(),
    dropoff_contact_family_name: z.string().optional(),
    dropoff_contact_send_notifications: z.boolean().optional(),
    dropoff_options: z.record(z.any()).optional(),
    dropoff_address_components: z.record(z.any()).optional(),
    dropoff_pin_code_verification_metadata: z.record(z.any()).optional(),
    shopping_options: z.record(z.any()).optional(),
    order_value: z.number().optional(),
    items: z.array(z.record(z.any())).optional(),
    pickup_time: z.string().optional(),
    dropoff_time: z.string().optional(),
    pickup_window: z.record(z.any()).optional(),
    dropoff_window: z.record(z.any()).optional(),
    customer_expected_sla: z.any().optional(),
    expires_by: z.any().optional(),
    shipping_label_metadata: z.record(z.any()).optional(),
    contactless_dropoff: z.boolean().optional(),
    action_if_undeliverable: z.string().optional(),
    tip: z.number().optional(),
    order_contains: z.record(z.any()).optional(),
    dasher_allowed_vehicles: z.array(z.string()).optional(),
    dropoff_requires_signature: z.boolean().optional(),
    promotion_id: z.string().optional(),
    dropoff_cash_on_delivery: z.number().optional(),
    order_route_type: z.string().optional(),
    order_route_items: z.array(z.string()).optional()
  },
  async (params) => {
    try {
      const response = await makeApiRequest(
        'https://openapi.doordash.com/drive/v2/quotes',
        'POST',
        params
      );
      return {
        content: [{ type: "text", text: String(JSON.stringify(response)) }]
      };
    } catch (error: any) {
      return {
        content: [{ type: "text", text: `Error: ${error.message}` }]
      };
    }
  }
);

// Tool: Accept Quote
server.tool("accept_quote",
  {
    external_delivery_id: z.string(),
    tip: z.number().optional(),
    dropoff_phone_number: z.string().optional()
  },
  async ({ external_delivery_id, tip, dropoff_phone_number }) => {
    try {
      const response = await makeApiRequest(
        `https://openapi.doordash.com/drive/v2/quotes/${external_delivery_id}/accept`,
        'POST',
        { tip: tip, dropoff_phone_number: dropoff_phone_number }
      );
      return {
        content: [{ type: "text", text: String(JSON.stringify(response)) }]
      };
    } catch (error: any) {
      return {
        content: [{ type: "text", text: `Error: ${error.message}` }]
      };
    }
  }
);

// Tool: Create Delivery
server.tool("create_delivery",
  {
    external_delivery_id: z.string(),
    locale: z.string().optional(),
    order_fulfillment_method: z.string().optional(),
    origin_facility_id: z.string().optional(),
    pickup_address: z.string().optional(),
    pickup_business_name: z.string().optional(),
    pickup_phone_number: z.string().optional(),
    pickup_instructions: z.string().optional(),
    pickup_reference_tag: z.string().optional(),
    pickup_external_business_id: z.string().optional(),
    pickup_external_store_id: z.string().optional(),
    pickup_verification_metadata: z.record(z.any()).optional(),
    dropoff_address: z.string(),
    dropoff_business_name: z.string().optional(),
    dropoff_location: z.record(z.any()).optional(),
    dropoff_phone_number: z.string(),
    dropoff_instructions: z.string().optional(),
    dropoff_contact_given_name: z.string().optional(),
    dropoff_contact_family_name: z.string().optional(),
    dropoff_contact_send_notifications: z.boolean().optional(),
    dropoff_options: z.record(z.any()).optional(),
    dropoff_address_components: z.record(z.any()).optional(),
    dropoff_pin_code_verification_metadata: z.record(z.any()).optional(),
    shopping_options: z.record(z.any()).optional(),
    order_value: z.number().optional(),
    items: z.array(z.record(z.any())).optional(),
    pickup_time: z.string().optional(),
    dropoff_time: z.string().optional(),
    pickup_window: z.record(z.any()).optional(),
    dropoff_window: z.record(z.any()).optional(),
    customer_expected_sla: z.any().optional(),
    expires_by: z.any().optional(),
    shipping_label_metadata: z.record(z.any()).optional(),
    contactless_dropoff: z.boolean().optional(),
    action_if_undeliverable: z.string().optional(),
    tip: z.number().optional(),
    order_contains: z.record(z.any()).optional(),
    dasher_allowed_vehicles: z.array(z.string()).optional(),
    dropoff_requires_signature: z.boolean().optional(),
    promotion_id: z.string().optional(),
    dropoff_cash_on_delivery: z.number().optional(),
    order_route_type: z.string().optional(),
    order_route_items: z.array(z.string()).optional()
  },
  async (params) => {
    try {
      const response = await makeApiRequest(
        'https://openapi.doordash.com/drive/v2/deliveries',
        'POST',
        params
      );
      return {
        content: [{ type: "text", text: String(JSON.stringify(response)) }]
      };
    } catch (error: any) {
      return {
        content: [{ type: "text", text: `Error: ${error.message}` }]
      };
    }
  }
);

// Tool: Get Delivery
server.tool("get_delivery",
  {
    external_delivery_id: z.string()
  },
  async ({ external_delivery_id }) => {
    try {
      const response = await makeApiRequest(
        `https://openapi.doordash.com/drive/v2/deliveries/${external_delivery_id}`,
        'GET'
      );
      return {
        content: [{ type: "text", text: String(JSON.stringify(response)) }]
      };
    } catch (error: any) {
      return {
        content: [{ type: "text", text: `Error: ${error.message}` }]
      };
    }
  }
);

// Tool: Update Delivery
server.tool("update_delivery",
  {
    external_delivery_id: z.string(),
    pickup_address: z.string().optional(),
    pickup_business_name: z.string().optional(),
    pickup_phone_number: z.string().optional(),
    pickup_instructions: z.string().optional(),
    pickup_reference_tag: z.string().optional(),
    pickup_external_business_id: z.string().optional(),
    pickup_external_store_id: z.string().optional(),
    pickup_verification_metadata: z.record(z.any()).optional(),
    dropoff_address: z.string().optional(),
    dropoff_business_name: z.string().optional(),
    dropoff_location: z.record(z.any()).optional(),
    dropoff_phone_number: z.string().optional(),
    dropoff_instructions: z.string().optional(),
    dropoff_contact_given_name: z.string().optional(),
    dropoff_contact_family_name: z.string().optional(),
    dropoff_contact_send_notifications: z.boolean().optional(),
    dropoff_options: z.record(z.any()).optional(),
    dropoff_address_components: z.record(z.any()).optional(),
    dropoff_pin_code_verification_metadata: z.record(z.any()).optional(),
    contactless_dropoff: z.boolean().optional(),
    action_if_undeliverable: z.string().optional(),
    tip: z.number().optional(),
    order_contains: z.record(z.any()).optional(),
    dasher_allowed_vehicles: z.array(z.string()).optional(),
    dropoff_requires_signature: z.boolean().optional(),
    promotion_id: z.string().optional(),
    dropoff_cash_on_delivery: z.number().optional(),
    order_route_type: z.string().optional(),
    order_route_items: z.array(z.string()).optional(),
    order_value: z.number().optional(),
    items: z.array(z.record(z.any())).optional(),
    pickup_time: z.string().optional(),
    dropoff_time: z.string().optional(),
    pickup_window: z.record(z.any()).optional(),
    dropoff_window: z.record(z.any()).optional(),
    customer_expected_sla: z.any().optional(),
    expires_by: z.any().optional(),
    shipping_label_metadata: z.record(z.any()).optional(),
  },
  async ({ external_delivery_id, ...params }) => {
    try {
      const response = await makeApiRequest(
        `https://openapi.doordash.com/drive/v2/deliveries/${external_delivery_id}`,
        'PATCH',
        params
      );
      return {
        content: [{ type: "text", text: String(JSON.stringify(response)) }]
      };
    } catch (error: any) {
      return {
        content: [{ type: "text", text: `Error: ${error.message}` }]
      };
    }
  }
);

// Tool: Cancel Delivery
server.tool("cancel_delivery",
  {
    external_delivery_id: z.string()
  },
  async ({ external_delivery_id }) => {
    try {
      const response = await makeApiRequest(
        `https://openapi.doordash.com/drive/v2/deliveries/${external_delivery_id}/cancel`,
        'PUT'
      );
      return {
        content: [{ type: "text", text: String(JSON.stringify(response)) }]
      };
    } catch (error: any) {
      return {
        content: [{ type: "text", text: `Error: ${error.message}` }]
      };
    }
  }
);

// Tool: Get Items Substitution Recommendation
server.tool("get_items_substitution_recommendation",
  {
    pickup_external_business_id: z.string(),
    pickup_external_store_id: z.string(),
    items: z.array(z.record(z.any())),
    customer: z.record(z.any()).optional()
  },
  async (params) => {
    try {
      const response = await makeApiRequest(
        'https://openapi.doordash.com/drive/v2/items_substitution_recommendation',
        'POST',
        params
      );
      return {
        content: [{ type: "text", text: String(JSON.stringify(response)) }]
      };
    } catch (error: any) {
      return {
        content: [{ type: "text", text: `Error: ${error.message}` }]
      };
    }
  }
);

// Tool: Create Checkout Audit Signal
server.tool("create_checkout_audit_signal",
  {
    external_delivery_id: z.string(),
    is_audit_successful: z.boolean(),
    audit_period: z.record(z.any()).optional(),
    requested_audit_item_count: z.number().optional(),
    audited_item_count: z.number().optional(),
    successful_audit_items: z.array(z.record(z.any())).optional(),
    failed_audit_items: z.array(z.record(z.any())).optional(),
    checkout_audit_status: z.string().optional()
  },
  async (params) => {
    try {
      const response = await makeApiRequest(
        'https://openapi.doordash.com/drive/v2/checkout_audit_signal',
        'POST',
        params
      );
      return {
        content: [{ type: "text", text: String(JSON.stringify(response)) }]
      };
    } catch (error: any) {
      return {
        content: [{ type: "text", text: `Error: ${error.message}` }]
      };
    }
  }
);

// Tool: Get Business
server.tool("get_business",
  {
    external_business_id: z.string()
  },
  async ({ external_business_id }) => {
    try {
      const response = await makeApiRequest(
        `https://openapi.doordash.com/developer/v1/businesses/${external_business_id}`,
        'GET'
      );
      return {
        content: [{ type: "text", text: String(JSON.stringify(response)) }]
      };
    } catch (error: any) {
      return {
        content: [{ type: "text", text: `Error: ${error.message}` }]
      };
    }
  }
);

// Tool: Update Business
server.tool("update_business",
  {
    external_business_id: z.string(),
    name: z.string().optional(),
    description: z.string().optional(),
    activation_status: z.string().optional()
  },
  async ({ external_business_id, name, description, activation_status }) => {
    try {
      const response = await makeApiRequest(
        `https://openapi.doordash.com/developer/v1/businesses/${external_business_id}`,
        'PATCH',
        { name: name, description: description, activation_status: activation_status }
      );
      return {
        content: [{ type: "text", text: String(JSON.stringify(response)) }]
      };
    } catch (error: any) {
      return {
        content: [{ type: "text", text: `Error: ${error.message}` }]
      };
    }
  }
);

// Tool: List Businesses
server.tool("list_businesses",
  {
    activationStatus: z.string().optional(),
    continuationToken: z.string().optional()
  },
  async ({ activationStatus, continuationToken }) => {
    try {
      let url = 'https://openapi.doordash.com/developer/v1/businesses';
      const params = new URLSearchParams();
      if (activationStatus) {
        params.append('activationStatus', activationStatus);
      }
      if (continuationToken) {
        params.append('continuationToken', continuationToken);
      }
      if (params.toString()) {
        url += `?${params.toString()}`;
      }
      const response = await makeApiRequest(url, 'GET');
      return {
        content: [{ type: "text", text: String(JSON.stringify(response)) }]
      };
    } catch (error: any) {
      return {
        content: [{ type: "text", text: `Error: ${error.message}` }]
      };
    }
  }
);

// Tool: Get Store
server.tool("get_store",
  {
    external_business_id: z.string(),
    external_store_id: z.string()
  },
  async ({ external_business_id, external_store_id }) => {
    try {
      const response = await makeApiRequest(
        `https://openapi.doordash.com/developer/v1/businesses/${external_business_id}/stores/${external_store_id}`,
        'GET'
      );
      return {
        content: [{ type: "text", text: String(JSON.stringify(response)) }]
      };
    } catch (error: any) {
      return {
        content: [{ type: "text", text: `Error: ${error.message}` }]
      };
    }
  }
);

// Tool: Update Store
server.tool("update_store",
  {
    external_business_id: z.string(),
    external_store_id: z.string(),
    name: z.string().optional(),
    phone_number: z.string().optional(),
    address: z.string().optional()
  },
  async ({ external_business_id, external_store_id, name, phone_number, address }) => {
    try {
      const response = await makeApiRequest(
        `https://openapi.doordash.com/developer/v1/businesses/${external_business_id}/stores/${external_store_id}`,
        'PATCH',
        { name: name, phone_number: phone_number, address: address }
      );
      return {
        content: [{ type: "text", text: String(JSON.stringify(response)) }]
      };
    } catch (error: any) {
      return {
        content: [{ type: "text", text: `Error: ${error.message}` }]
      };
    }
  }
);

// Tool: Create Store
server.tool("create_store",
  {
    external_business_id: z.string(),
    external_store_id: z.string(),
    name: z.string(),
    phone_number: z.string(),
    address: z.string()
  },
  async ({ external_business_id, external_store_id, name, phone_number, address }) => {
    try {
      const response = await makeApiRequest(
        `https://openapi.doordash.com/developer/v1/businesses/${external_business_id}/stores`,
        'POST',
        { external_store_id: external_store_id, name: name, phone_number: phone_number, address: address }
      );
      return {
        content: [{ type: "text", text: String(JSON.stringify(response)) }]
      };
    } catch (error: any) {
      return {
        content: [{ type: "text", text: `Error: ${error.message}` }]
      };
    }
  }
);

// Tool: List Stores
server.tool("list_stores",
  {
    external_business_id: z.string(),
    activationStatus: z.string().optional(),
    continuationToken: z.string().optional()
  },
  async ({ external_business_id, activationStatus, continuationToken }) => {
    try {
      let url = `https://openapi.doordash.com/developer/v1/businesses/${external_business_id}/stores`;
      const params = new URLSearchParams();
      if (activationStatus) {
        params.append('activationStatus', activationStatus);
      }
      if (continuationToken) {
        params.append('continuationToken', continuationToken);
      }
      if (params.toString()) {
        url += `?${params.toString()}`;
      }
      const response = await makeApiRequest(url, 'GET');
      return {
        content: [{ type: "text", text: String(JSON.stringify(response)) }]
      };
    } catch (error: any) {
      return {
        content: [{ type: "text", text: `Error: ${error.message}` }]
      };
    }
  }
);

// Start receiving messages on stdin and sending messages on stdout
const transport = new StdioServerTransport();
await server.connect(transport);
```