Elsevier Capabilities
Naftiko 0.5 capability definitions for Elsevier - 100 capabilities showing integration workflows and service orchestrations.
Given an article abstract, calls the Anthropic API to generate a plain-language summary suitable for social media promotion, then stores the result in Salesforce.
naftiko: "0.5"
info:
label: "AI-Assisted Abstract Summarization"
description: "Given an article abstract, calls the Anthropic API to generate a plain-language summary suitable for social media promotion, then stores the result in Salesforce."
tags:
- ai
- publishing
- content
- anthropic
- salesforce
- automation
capability:
exposes:
- type: mcp
namespace: ai-content
port: 8080
tools:
- name: summarize-abstract
description: "Given an article DOI and abstract text, call Anthropic Claude to generate a plain-language summary and a social media teaser, then store both in the Salesforce article record. Use for post-acceptance content marketing preparation."
inputParameters:
- name: article_doi
in: body
type: string
description: "Article DOI for the accepted manuscript."
- name: abstract_text
in: body
type: string
description: "Full abstract text from the manuscript."
steps:
- name: generate-summary
type: call
call: anthropic.create-message
with:
model: "claude-opus-4-5"
max_tokens: "500"
system: "You are a science communicator. Summarize the following abstract in plain language suitable for a general audience in 2-3 sentences, then provide a 280-character social media teaser."
user_content: "{{abstract_text}}"
- name: store-summary
type: call
call: salesforce.patch-article-summary
with:
doi__c: "{{article_doi}}"
Plain_Language_Summary__c: "{{generate-summary.summary}}"
Social_Teaser__c: "{{generate-summary.teaser}}"
consumes:
- type: http
namespace: anthropic
baseUri: "https://api.anthropic.com/v1"
authentication:
type: apikey
key: "x-api-key"
value: "$secrets.anthropic_api_key"
placement: header
resources:
- name: messages
path: "/messages"
operations:
- name: create-message
method: POST
- type: http
namespace: salesforce
baseUri: "https://elsevier.my.salesforce.com/services/data/v58.0"
authentication:
type: bearer
token: "$secrets.salesforce_token"
resources:
- name: article-records
path: "/query"
inputParameters:
- name: doi__c
in: query
operations:
- name: patch-article-summary
method: PATCH
Executes a SQL query against Amazon Redshift for content analytics lookups.
naftiko: "0.5"
info:
label: "Amazon Redshift Analytics Query"
description: "Executes a SQL query against Amazon Redshift for content analytics lookups."
tags:
- data
- analytics
- amazon-redshift
capability:
exposes:
- type: mcp
namespace: data-ops
port: 8080
tools:
- name: run-redshift-query
description: "Given a SQL query, execute against Redshift and return results."
inputParameters:
- name: sql
in: body
type: string
description: "SQL query."
call: redshift.execute-statement
with:
sql: "{{sql}}"
database: "content_analytics"
outputParameters:
- name: statement_id
type: string
mapping: "$.Id"
consumes:
- type: http
namespace: redshift
baseUri: "https://redshift-data.eu-west-1.amazonaws.com"
authentication:
type: aws-sigv4
accessKeyId: "$secrets.aws_access_key"
secretAccessKey: "$secrets.aws_secret_key"
resources:
- name: statements
path: "/"
operations:
- name: execute-statement
method: POST
Checks the depth of an SQS queue and returns message counts.
naftiko: "0.5"
info:
label: "Amazon SQS Message Monitor"
description: "Checks the depth of an SQS queue and returns message counts."
tags:
- engineering
- messaging
- amazon-sqs
capability:
exposes:
- type: mcp
namespace: platform-ops
port: 8080
tools:
- name: get-queue-depth
description: "Given an SQS queue URL, return approximate message count."
inputParameters:
- name: queue_url
in: body
type: string
description: "SQS queue URL."
call: sqs.get-queue-attributes
with:
queue_url: "{{queue_url}}"
outputParameters:
- name: messages
type: integer
mapping: "$.Attributes.ApproximateNumberOfMessages"
consumes:
- type: http
namespace: sqs
baseUri: "https://sqs.eu-west-1.amazonaws.com"
authentication:
type: aws-sigv4
accessKeyId: "$secrets.aws_access_key"
secretAccessKey: "$secrets.aws_secret_key"
resources:
- name: queues
path: "/"
operations:
- name: get-queue-attributes
method: POST
Looks up an article DOI in Salesforce to verify the institution's subscription entitlement, returning access level and license terms.
naftiko: "0.5"
info:
label: "Article Access License Check"
description: "Looks up an article DOI in Salesforce to verify the institution's subscription entitlement, returning access level and license terms."
tags:
- publishing
- licensing
- crm
- salesforce
capability:
exposes:
- type: mcp
namespace: licensing
port: 8080
tools:
- name: get-article-access
description: "Given an article DOI and an institution ID, check the Salesforce subscription record to determine access level (open-access, subscribed, pay-per-view). Use when resolving reader access disputes."
inputParameters:
- name: doi
in: body
type: string
description: "Article DOI in the format 10.XXXX/YYYY."
- name: institution_id
in: body
type: string
description: "Salesforce account ID for the subscribing institution."
call: salesforce.get-entitlement
with:
doi__c: "{{doi}}"
account_id: "{{institution_id}}"
outputParameters:
- name: access_level
type: string
mapping: "$.records[0].Access_Level__c"
- name: license_type
type: string
mapping: "$.records[0].License_Type__c"
- name: expiry_date
type: string
mapping: "$.records[0].License_Expiry__c"
consumes:
- type: http
namespace: salesforce
baseUri: "https://elsevier.my.salesforce.com/services/data/v58.0"
authentication:
type: bearer
token: "$secrets.salesforce_token"
resources:
- name: entitlements
path: "/query"
inputParameters:
- name: doi__c
in: query
- name: account_id
in: query
operations:
- name: get-entitlement
method: GET
When a manuscript is submitted via the editorial system, creates a Salesforce opportunity record for the journal, assigns a handling editor in Workday, and sends a confirmation via Microsoft Teams.
naftiko: "0.5"
info:
label: "Author Submission Intake"
description: "When a manuscript is submitted via the editorial system, creates a Salesforce opportunity record for the journal, assigns a handling editor in Workday, and sends a confirmation via Microsoft Teams."
tags:
- publishing
- crm
- hr
- salesforce
- workday
- msteams
- onboarding
capability:
exposes:
- type: mcp
namespace: publishing-intake
port: 8080
tools:
- name: create-submission-record
description: "Given a manuscript ID and journal code, create a Salesforce opportunity for the submission, look up the handling editor in Workday, and send a Teams notification to the editorial team."
inputParameters:
- name: manuscript_id
in: body
type: string
description: "Unique manuscript identifier from the editorial submission system."
- name: journal_code
in: body
type: string
description: "Short journal code (e.g., JBC, CELL) identifying the target publication."
- name: author_email
in: body
type: string
description: "Corresponding author email address for record linkage."
steps:
- name: create-opportunity
type: call
call: salesforce.create-opportunity
with:
Name: "Manuscript {{manuscript_id}} — {{journal_code}}"
StageName: "Submission Review"
CloseDate: "2026-12-31"
Journal_Code__c: "{{journal_code}}"
- name: get-editor
type: call
call: workday.get-worker-by-role
with:
role: "handling_editor"
department: "{{journal_code}}"
- name: notify-team
type: call
call: msteams.send-message
with:
channel: "editorial-alerts"
text: "New submission {{manuscript_id}} received for {{journal_code}}. Assigned editor: {{get-editor.full_name}}. SF record: {{create-opportunity.id}}"
consumes:
- type: http
namespace: salesforce
baseUri: "https://elsevier.my.salesforce.com/services/data/v58.0"
authentication:
type: bearer
token: "$secrets.salesforce_token"
resources:
- name: opportunities
path: "/sobjects/Opportunity"
operations:
- name: create-opportunity
method: POST
- type: http
namespace: workday
baseUri: "https://wd2-impl-services1.workday.com/ccx/api/v1"
authentication:
type: bearer
token: "$secrets.workday_token"
resources:
- name: workers
path: "/workers"
inputParameters:
- name: role
in: query
- name: department
in: query
operations:
- name: get-worker-by-role
method: GET
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/editorial/channels/general/messages"
operations:
- name: send-message
method: POST
Searches CloudWatch Logs by filter pattern and returns matching log events.
naftiko: "0.5"
info:
label: "AWS CloudWatch Log Search"
description: "Searches CloudWatch Logs by filter pattern and returns matching log events."
tags:
- engineering
- monitoring
- aws
- cloudwatch
capability:
exposes:
- type: mcp
namespace: platform-ops
port: 8080
tools:
- name: search-logs
description: "Given a log group and filter pattern, return matching CloudWatch log events."
inputParameters:
- name: log_group
in: body
type: string
description: "CloudWatch log group name."
- name: filter_pattern
in: body
type: string
description: "Filter pattern."
call: cloudwatch.filter-log-events
with:
log_group: "{{log_group}}"
filter_pattern: "{{filter_pattern}}"
outputParameters:
- name: events
type: array
mapping: "$.events"
consumes:
- type: http
namespace: cloudwatch
baseUri: "https://logs.eu-west-1.amazonaws.com"
authentication:
type: aws-sigv4
accessKeyId: "$secrets.aws_access_key"
secretAccessKey: "$secrets.aws_secret_key"
resources:
- name: logs
path: "/"
operations:
- name: filter-log-events
method: POST
Retrieves the running state of an EC2 instance by ID.
naftiko: "0.5"
info:
label: "AWS EC2 Instance Status"
description: "Retrieves the running state of an EC2 instance by ID."
tags:
- cloud
- infrastructure
- aws
- ec2
capability:
exposes:
- type: mcp
namespace: cloud-ops
port: 8080
tools:
- name: get-ec2-status
description: "Given an EC2 instance ID, return the state and instance type."
inputParameters:
- name: instance_id
in: body
type: string
description: "EC2 instance ID."
call: ec2.describe-instance
with:
instance_id: "{{instance_id}}"
outputParameters:
- name: state
type: string
mapping: "$.Reservations[0].Instances[0].State.Name"
- name: instance_type
type: string
mapping: "$.Reservations[0].Instances[0].InstanceType"
consumes:
- type: http
namespace: ec2
baseUri: "https://ec2.eu-west-1.amazonaws.com"
authentication:
type: aws-sigv4
accessKeyId: "$secrets.aws_access_key"
secretAccessKey: "$secrets.aws_secret_key"
resources:
- name: instances
path: "/"
operations:
- name: describe-instance
method: GET
Invokes an AWS Lambda function to resolve a DOI and return the canonical article URL and metadata.
naftiko: "0.5"
info:
label: "AWS Lambda DOI Resolver"
description: "Invokes an AWS Lambda function to resolve a DOI and return the canonical article URL and metadata."
tags:
- publishing
- serverless
- aws
- aws-lambda
capability:
exposes:
- type: mcp
namespace: publishing-ops
port: 8080
tools:
- name: resolve-doi
description: "Given a DOI, invoke the DOI resolver Lambda and return the canonical URL."
inputParameters:
- name: doi
in: body
type: string
description: "Article DOI."
call: lambda.invoke-function
with:
function_name: "doi-resolver"
payload: "{\"doi\": \"{{doi}}\"}"
outputParameters:
- name: canonical_url
type: string
mapping: "$.body.url"
- name: title
type: string
mapping: "$.body.title"
consumes:
- type: http
namespace: lambda
baseUri: "https://lambda.eu-west-1.amazonaws.com/2015-03-31"
authentication:
type: aws-sigv4
accessKeyId: "$secrets.aws_access_key"
secretAccessKey: "$secrets.aws_secret_key"
resources:
- name: functions
path: "/functions/doi-resolver/invocations"
operations:
- name: invoke-function
method: POST
Triggers a content backup job to S3 and posts confirmation to the platform ops Slack channel.
naftiko: "0.5"
info:
label: "AWS S3 Content Backup"
description: "Triggers a content backup job to S3 and posts confirmation to the platform ops Slack channel."
tags:
- data
- storage
- amazon-s3
- slack
capability:
exposes:
- type: mcp
namespace: backup-ops
port: 8080
tools:
- name: trigger-content-backup
description: "Trigger a content backup to S3 and notify ops via Slack."
inputParameters:
- name: bucket
in: body
type: string
description: "S3 backup bucket."
- name: prefix
in: body
type: string
description: "S3 key prefix for the backup."
steps:
- name: start-backup
type: call
call: s3.initiate-backup
with:
bucket: "{{bucket}}"
prefix: "{{prefix}}"
- name: notify-ops
type: call
call: slack.post-message
with:
channel: "platform-ops"
text: "Content backup initiated to s3://{{bucket}}/{{prefix}}"
consumes:
- type: http
namespace: s3
baseUri: "https://s3.eu-west-1.amazonaws.com"
authentication:
type: aws-sigv4
accessKeyId: "$secrets.aws_access_key"
secretAccessKey: "$secrets.aws_secret_key"
resources:
- name: objects
path: "/{{bucket}}/{{prefix}}"
inputParameters:
- name: bucket
in: path
- name: prefix
in: path
operations:
- name: initiate-backup
method: PUT
- type: http
namespace: slack
baseUri: "https://slack.com/api"
authentication:
type: bearer
token: "$secrets.slack_bot_token"
resources:
- name: messages
path: "/chat.postMessage"
operations:
- name: post-message
method: POST
Updates Azure AD group memberships when an employee changes teams in Workday.
naftiko: "0.5"
info:
label: "Azure AD Group Sync"
description: "Updates Azure AD group memberships when an employee changes teams in Workday."
tags:
- identity
- hr
- azure-active-directory
- workday
capability:
exposes:
- type: mcp
namespace: iam-ops
port: 8080
tools:
- name: sync-ad-groups
description: "Given a Workday employee ID and new team, update Azure AD group memberships."
inputParameters:
- name: employee_id
in: body
type: string
description: "Workday employee ID."
- name: new_team
in: body
type: string
description: "New team code."
steps:
- name: get-worker
type: call
call: workday.get-worker
with:
employee_id: "{{employee_id}}"
- name: update-groups
type: call
call: azuread.update-membership
with:
user_email: "{{get-worker.email}}"
team: "{{new_team}}"
consumes:
- type: http
namespace: workday
baseUri: "https://wd5-impl-services1.workday.com/ccx/service/elsevier"
authentication:
type: basic
username: "$secrets.workday_user"
password: "$secrets.workday_password"
resources:
- name: workers
path: "/Human_Resources/v40.0/Get_Workers"
operations:
- name: get-worker
method: GET
- type: http
namespace: azuread
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msgraph_token"
resources:
- name: groups
path: "/groups"
operations:
- name: update-membership
method: POST
Uploads a finalized manuscript PDF to Azure Blob Storage for long-term archival and logs the action to ServiceNow.
naftiko: "0.5"
info:
label: "Azure Blob Manuscript Archive"
description: "Uploads a finalized manuscript PDF to Azure Blob Storage for long-term archival and logs the action to ServiceNow."
tags:
- publishing
- storage
- azure-blob-storage
- servicenow
capability:
exposes:
- type: mcp
namespace: archive-ops
port: 8080
tools:
- name: archive-manuscript
description: "Given a manuscript ID and source URL, upload to Azure Blob Storage and create a ServiceNow archival record."
inputParameters:
- name: manuscript_id
in: body
type: string
description: "Manuscript ID."
- name: source_url
in: body
type: string
description: "Source URL of the manuscript PDF."
steps:
- name: upload-blob
type: call
call: azure-blob.upload
with:
container: "manuscripts-archive"
blob_name: "{{manuscript_id}}.pdf"
source_url: "{{source_url}}"
- name: log-archival
type: call
call: servicenow.create-record
with:
table: "u_manuscript_archive"
manuscript_id: "{{manuscript_id}}"
blob_url: "{{upload-blob.url}}"
consumes:
- type: http
namespace: azure-blob
baseUri: "https://elsevierstorage.blob.core.windows.net"
authentication:
type: bearer
token: "$secrets.azure_storage_token"
resources:
- name: blobs
path: "/{{container}}/{{blob_name}}"
inputParameters:
- name: container
in: path
- name: blob_name
in: path
operations:
- name: upload
method: PUT
- type: http
namespace: servicenow
baseUri: "https://elsevier.service-now.com/api/now"
authentication:
type: basic
username: "$secrets.servicenow_user"
password: "$secrets.servicenow_password"
resources:
- name: records
path: "/table/{{table}}"
inputParameters:
- name: table
in: path
operations:
- name: create-record
method: POST
Monitors Azure consumption for cost spikes above a daily threshold, writes anomalies to Snowflake, and pages the cloud operations team via ServiceNow and Teams.
naftiko: "0.5"
info:
label: "Azure Cloud Cost Anomaly Alert"
description: "Monitors Azure consumption for cost spikes above a daily threshold, writes anomalies to Snowflake, and pages the cloud operations team via ServiceNow and Teams."
tags:
- cloud
- finops
- azure
- snowflake
- servicenow
- msteams
- cost-management
capability:
exposes:
- type: mcp
namespace: cloud-finops
port: 8080
tools:
- name: alert-cost-anomaly
description: "Given an Azure subscription ID and a daily spend threshold in USD, fetch the current day's cost from Azure Cost Management, record the anomaly in Snowflake, and open a ServiceNow incident if the threshold is exceeded."
inputParameters:
- name: subscription_id
in: body
type: string
description: "Azure subscription ID to monitor."
- name: daily_threshold_usd
in: body
type: number
description: "Daily spend threshold in USD above which an alert is triggered."
steps:
- name: get-azure-cost
type: call
call: azure.get-daily-cost
with:
subscription_id: "{{subscription_id}}"
- name: write-cost-record
type: call
call: snowflake.insert-cost-row
with:
subscription_id: "{{subscription_id}}"
daily_cost: "{{get-azure-cost.total_cost}}"
- name: create-incident
type: call
call: servicenow.create-incident
with:
short_description: "Azure cost anomaly: subscription {{subscription_id}} exceeded ${{daily_threshold_usd}}/day"
urgency: "2"
description: "Current daily spend: ${{get-azure-cost.total_cost}}. Threshold: ${{daily_threshold_usd}}."
consumes:
- type: http
namespace: azure
baseUri: "https://management.azure.com"
authentication:
type: bearer
token: "$secrets.azure_token"
resources:
- name: cost-query
path: "/subscriptions/{{subscription_id}}/providers/Microsoft.CostManagement/query"
inputParameters:
- name: subscription_id
in: path
operations:
- name: get-daily-cost
method: POST
- type: http
namespace: snowflake
baseUri: "https://elsevier.snowflakecomputing.com/api/v2"
authentication:
type: bearer
token: "$secrets.snowflake_token"
resources:
- name: cost-records
path: "/statements"
operations:
- name: insert-cost-row
method: POST
- type: http
namespace: servicenow
baseUri: "https://elsevier.service-now.com/api/now"
authentication:
type: basic
username: "$secrets.servicenow_user"
password: "$secrets.servicenow_password"
resources:
- name: incidents
path: "/table/incident"
operations:
- name: create-incident
method: POST
Retrieves the latest build result for an Azure DevOps pipeline.
naftiko: "0.5"
info:
label: "Azure DevOps Build Monitor"
description: "Retrieves the latest build result for an Azure DevOps pipeline."
tags:
- engineering
- cicd
- azure-devops
capability:
exposes:
- type: mcp
namespace: cicd-ops
port: 8080
tools:
- name: get-build-result
description: "Given an Azure DevOps project and pipeline, return the latest build result."
inputParameters:
- name: project
in: body
type: string
description: "Azure DevOps project."
- name: pipeline_id
in: body
type: string
description: "Pipeline ID."
call: azdo.get-latest-build
with:
project: "{{project}}"
definition_id: "{{pipeline_id}}"
outputParameters:
- name: result
type: string
mapping: "$.value[0].result"
- name: commit
type: string
mapping: "$.value[0].sourceVersion"
consumes:
- type: http
namespace: azdo
baseUri: "https://dev.azure.com/elsevier"
authentication:
type: basic
username: ""
password: "$secrets.azdo_pat"
resources:
- name: builds
path: "/{{project}}/_apis/build/builds"
inputParameters:
- name: project
in: path
operations:
- name: get-latest-build
method: GET
Purges Cloudflare CDN cache for specific URLs and notifies the platform team via Slack.
naftiko: "0.5"
info:
label: "Cloudflare CDN Purge"
description: "Purges Cloudflare CDN cache for specific URLs and notifies the platform team via Slack."
tags:
- infrastructure
- cdn
- cloudflare
- slack
capability:
exposes:
- type: mcp
namespace: platform-ops
port: 8080
tools:
- name: purge-cdn-cache
description: "Given a Cloudflare zone ID and list of URLs, purge CDN cache and notify Slack."
inputParameters:
- name: zone_id
in: body
type: string
description: "Cloudflare zone ID."
- name: urls
in: body
type: string
description: "Comma-separated URLs to purge."
steps:
- name: purge-cache
type: call
call: cloudflare.purge-cache
with:
zone_id: "{{zone_id}}"
files: "{{urls}}"
- name: notify-team
type: call
call: slack.post-message
with:
channel: "platform-ops"
text: "CDN cache purged for zone {{zone_id}}: {{urls}}"
consumes:
- type: http
namespace: cloudflare
baseUri: "https://api.cloudflare.com/client/v4"
authentication:
type: bearer
token: "$secrets.cloudflare_token"
resources:
- name: purge
path: "/zones/{{zone_id}}/purge_cache"
inputParameters:
- name: zone_id
in: path
operations:
- name: purge-cache
method: POST
- type: http
namespace: slack
baseUri: "https://slack.com/api"
authentication:
type: bearer
token: "$secrets.slack_bot_token"
resources:
- name: messages
path: "/chat.postMessage"
operations:
- name: post-message
method: POST
Queries SAP Concur for expense reports pending approval beyond five business days, and sends reminder messages via Teams to the respective approvers.
naftiko: "0.5"
info:
label: "Concur Expense Report Approval Reminder"
description: "Queries SAP Concur for expense reports pending approval beyond five business days, and sends reminder messages via Teams to the respective approvers."
tags:
- finance
- expense-management
- sap-concur
- msteams
- approval
capability:
exposes:
- type: mcp
namespace: expense-ops
port: 8080
tools:
- name: send-expense-approval-reminders
description: "Query SAP Concur for expense reports that have been pending approval for more than a configurable number of days, then send a Teams reminder to each overdue approver. Use daily as part of finance operations."
inputParameters:
- name: pending_days_threshold
in: body
type: integer
description: "Number of business days an expense report can be pending before a reminder is sent (e.g., 5)."
steps:
- name: get-pending-reports
type: call
call: concur.get-pending-expense-reports
with:
pending_days: "{{pending_days_threshold}}"
- name: send-reminders
type: call
call: msteams.send-message
with:
channel: "finance-ops"
text: "Expense approval reminder: {{get-pending-reports.report_count}} reports pending over {{pending_days_threshold}} days. Approvers: {{get-pending-reports.approver_list}}"
consumes:
- type: http
namespace: concur
baseUri: "https://www.concursolutions.com/api/v3.0"
authentication:
type: bearer
token: "$secrets.concur_token"
resources:
- name: expense-reports
path: "/expense/reports"
inputParameters:
- name: pending_days
in: query
operations:
- name: get-pending-expense-reports
method: GET
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/finance/channels/general/messages"
operations:
- name: send-message
method: POST
Periodically audits Confluence knowledge base articles older than 180 days without updates, creates Jira tasks for content owners to review, and reports findings to the IT knowledge management team.
naftiko: "0.5"
info:
label: "Confluence Knowledge Article Quality Scan"
description: "Periodically audits Confluence knowledge base articles older than 180 days without updates, creates Jira tasks for content owners to review, and reports findings to the IT knowledge management team."
tags:
- itsm
- knowledge-management
- confluence
- jira
- msteams
capability:
exposes:
- type: mcp
namespace: knowledge-ops
port: 8080
tools:
- name: audit-stale-kb-articles
description: "Given a Confluence space key and a staleness threshold in days, list pages not updated within the threshold, create a Jira task for each stale article owner, and post a summary to the IT Teams channel."
inputParameters:
- name: confluence_space_key
in: body
type: string
description: "Confluence space key to audit (e.g., ITSUPPORT)."
- name: stale_days_threshold
in: body
type: integer
description: "Number of days since last update before an article is considered stale (e.g., 180)."
steps:
- name: list-stale-pages
type: call
call: confluence.get-stale-pages
with:
space_key: "{{confluence_space_key}}"
days: "{{stale_days_threshold}}"
- name: create-review-tasks
type: call
call: jira.create-issue
with:
project_key: "KM"
issuetype: "Task"
summary: "KB article review: {{list-stale-pages.stale_count}} stale pages in {{confluence_space_key}}"
description: "Pages requiring review: {{list-stale-pages.page_titles}}"
- name: notify-team
type: call
call: msteams.send-message
with:
channel: "it-knowledge-mgmt"
text: "KB audit: {{list-stale-pages.stale_count}} articles in {{confluence_space_key}} not updated in {{stale_days_threshold}} days. Jira: {{create-review-tasks.key}}"
consumes:
- type: http
namespace: confluence
baseUri: "https://elsevier.atlassian.net/wiki/rest/api"
authentication:
type: basic
username: "$secrets.confluence_user"
password: "$secrets.confluence_api_token"
resources:
- name: pages
path: "/space/{{space_key}}/content/page"
inputParameters:
- name: space_key
in: path
- name: days
in: query
operations:
- name: get-stale-pages
method: GET
- type: http
namespace: jira
baseUri: "https://elsevier.atlassian.net/rest/api/3"
authentication:
type: basic
username: "$secrets.jira_user"
password: "$secrets.jira_api_token"
resources:
- name: issues
path: "/issue"
operations:
- name: create-issue
method: POST
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/it/channels/knowledge-mgmt/messages"
operations:
- name: send-message
method: POST
Searches the Confluence knowledge base by keyword and returns matching page titles and URLs.
naftiko: "0.5"
info:
label: "Confluence Knowledge Base Search"
description: "Searches the Confluence knowledge base by keyword and returns matching page titles and URLs."
tags:
- documentation
- collaboration
- confluence
capability:
exposes:
- type: mcp
namespace: docs-ops
port: 8080
tools:
- name: search-kb
description: "Given a search keyword, find matching knowledge base articles in Confluence."
inputParameters:
- name: keyword
in: body
type: string
description: "Search keyword."
call: confluence.search
with:
cql: "type=page AND text~'{{keyword}}'"
outputParameters:
- name: results
type: array
mapping: "$.results[*]"
consumes:
- type: http
namespace: confluence
baseUri: "https://elsevier.atlassian.net/wiki/rest/api"
authentication:
type: basic
username: "$secrets.confluence_user"
password: "$secrets.confluence_token"
resources:
- name: search
path: "/search"
operations:
- name: search
method: GET
When Datadog detects a content delivery error spike, creates a ServiceNow incident, notifies the platform engineering channel in Teams, and opens a Jira bug for root-cause tracking.
naftiko: "0.5"
info:
label: "Content Platform Incident Response"
description: "When Datadog detects a content delivery error spike, creates a ServiceNow incident, notifies the platform engineering channel in Teams, and opens a Jira bug for root-cause tracking."
tags:
- itsm
- incident-response
- datadog
- servicenow
- jira
- msteams
- devops
capability:
exposes:
- type: mcp
namespace: platform-ops
port: 8080
tools:
- name: handle-content-incident
description: "Given a Datadog alert ID and affected service name, create a P1 ServiceNow incident, post a Teams alert to the platform-engineering channel, and open a Jira bug. Use when automated alerting detects SLA-breaching errors."
inputParameters:
- name: alert_id
in: body
type: string
description: "Datadog monitor alert ID that triggered this incident."
- name: service_name
in: body
type: string
description: "Affected service name (e.g., sciencedirect-content-api)."
- name: severity
in: body
type: string
description: "Incident severity: P1, P2, or P3."
steps:
- name: get-alert-details
type: call
call: datadog.get-monitor-alert
with:
alert_id: "{{alert_id}}"
- name: create-incident
type: call
call: servicenow.create-incident
with:
short_description: "[{{severity}}] Content platform degradation: {{service_name}}"
urgency: "1"
impact: "1"
description: "Datadog alert {{alert_id}}: {{get-alert-details.message}}"
- name: create-bug
type: call
call: jira.create-issue
with:
project_key: "PLAT"
issuetype: "Bug"
summary: "[{{severity}}] {{service_name}} content delivery failure"
description: "Incident: {{create-incident.number}} | Alert: {{alert_id}} | Details: {{get-alert-details.message}}"
- name: notify-teams
type: call
call: msteams.send-channel-message
with:
channel: "platform-engineering"
text: "INCIDENT {{create-incident.number}} | {{severity}} | {{service_name}} | Jira: {{create-bug.key}}"
consumes:
- type: http
namespace: datadog
baseUri: "https://api.datadoghq.com/api/v1"
authentication:
type: apikey
key: "DD-API-KEY"
value: "$secrets.datadog_api_key"
placement: header
resources:
- name: monitor-alerts
path: "/monitor/{{alert_id}}"
inputParameters:
- name: alert_id
in: path
operations:
- name: get-monitor-alert
method: GET
- type: http
namespace: servicenow
baseUri: "https://elsevier.service-now.com/api/now"
authentication:
type: basic
username: "$secrets.servicenow_user"
password: "$secrets.servicenow_password"
resources:
- name: incidents
path: "/table/incident"
operations:
- name: create-incident
method: POST
- type: http
namespace: jira
baseUri: "https://elsevier.atlassian.net/rest/api/3"
authentication:
type: basic
username: "$secrets.jira_user"
password: "$secrets.jira_api_token"
resources:
- name: issues
path: "/issue"
operations:
- name: create-issue
method: POST
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/platform/channels/general/messages"
operations:
- name: send-channel-message
method: POST
Retrieves article metadata from Crossref by DOI, returning title, authors, journal, and publication date.
naftiko: "0.5"
info:
label: "Crossref DOI Metadata Lookup"
description: "Retrieves article metadata from Crossref by DOI, returning title, authors, journal, and publication date."
tags:
- publishing
- metadata
- crossref
capability:
exposes:
- type: mcp
namespace: publishing-ops
port: 8080
tools:
- name: get-doi-metadata
description: "Given a DOI, return the article title, authors, journal name, and publication date from Crossref."
inputParameters:
- name: doi
in: body
type: string
description: "Article DOI."
call: crossref.get-work
with:
doi: "{{doi}}"
outputParameters:
- name: title
type: string
mapping: "$.message.title[0]"
- name: journal
type: string
mapping: "$.message.container-title[0]"
consumes:
- type: http
namespace: crossref
baseUri: "https://api.crossref.org"
authentication:
type: none
resources:
- name: works
path: "/works/{{doi}}"
inputParameters:
- name: doi
in: path
operations:
- name: get-work
method: GET
Retrieves the status of a Databricks content processing pipeline job run by run ID.
naftiko: "0.5"
info:
label: "Databricks Content Pipeline Status"
description: "Retrieves the status of a Databricks content processing pipeline job run by run ID."
tags:
- data-engineering
- publishing
- databricks
capability:
exposes:
- type: mcp
namespace: data-ops
port: 8080
tools:
- name: get-pipeline-status
description: "Given a Databricks run ID, return the pipeline state, start time, and result."
inputParameters:
- name: run_id
in: body
type: string
description: "Databricks job run ID."
call: databricks.get-run
with:
run_id: "{{run_id}}"
outputParameters:
- name: state
type: string
mapping: "$.state.life_cycle_state"
- name: result
type: string
mapping: "$.state.result_state"
consumes:
- type: http
namespace: databricks
baseUri: "https://elsevier.cloud.databricks.com/api/2.1"
authentication:
type: bearer
token: "$secrets.databricks_token"
resources:
- name: runs
path: "/jobs/runs/get"
inputParameters:
- name: run_id
in: query
operations:
- name: get-run
method: GET
Queries Datadog for platform service health metrics and posts a status summary to Microsoft Teams.
naftiko: "0.5"
info:
label: "Datadog Platform Health Check"
description: "Queries Datadog for platform service health metrics and posts a status summary to Microsoft Teams."
tags:
- monitoring
- observability
- datadog
- microsoft-teams
capability:
exposes:
- type: mcp
namespace: platform-ops
port: 8080
tools:
- name: check-platform-health
description: "Query Datadog for key platform metrics and post a health summary to the ops Teams channel."
inputParameters:
- name: service_name
in: body
type: string
description: "Service name to check."
steps:
- name: query-health
type: call
call: datadog.query-timeseries
with:
query: "avg:trace.http.request.duration{service:{{service_name}}}.as_rate()"
- name: post-status
type: call
call: msteams.post-channel-message
with:
channel_id: "platform-ops"
text: "Health check for {{service_name}}: avg latency = {{query-health.series[0].pointlist[-1][1]}}ms"
consumes:
- type: http
namespace: datadog
baseUri: "https://api.datadoghq.com/api/v1"
authentication:
type: apikey
key: "DD-API-KEY"
value: "$secrets.datadog_api_key"
placement: header
resources:
- name: query
path: "/query"
operations:
- name: query-timeseries
method: GET
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/{{team_id}}/channels/{{channel_id}}/messages"
inputParameters:
- name: channel_id
in: path
operations:
- name: post-channel-message
method: POST
Queries Datadog for all defined SLOs on content platform services, computes compliance rates, writes results to Snowflake, and alerts engineering leadership via Teams when SLOs are at risk.
naftiko: "0.5"
info:
label: "Datadog SLO Compliance Report"
description: "Queries Datadog for all defined SLOs on content platform services, computes compliance rates, writes results to Snowflake, and alerts engineering leadership via Teams when SLOs are at risk."
tags:
- observability
- slo
- datadog
- snowflake
- msteams
- reporting
capability:
exposes:
- type: mcp
namespace: slo-reporting
port: 8080
tools:
- name: report-slo-compliance
description: "Given a service tag and time window, fetch SLO status from Datadog, persist results to Snowflake, and post a Teams alert if any SLO is below 99.5%. Use weekly for service reliability reviews."
inputParameters:
- name: service_tag
in: body
type: string
description: "Datadog service tag to filter SLOs (e.g., service:sciencedirect)."
- name: time_window
in: body
type: string
description: "SLO evaluation window: 7d, 30d, or 90d."
steps:
- name: get-slo-status
type: call
call: datadog.list-slos
with:
tags: "{{service_tag}}"
time_window: "{{time_window}}"
- name: write-slo-data
type: call
call: snowflake.insert-slo-row
with:
service_tag: "{{service_tag}}"
time_window: "{{time_window}}"
at_risk_count: "{{get-slo-status.at_risk_count}}"
- name: alert-leadership
type: call
call: msteams.send-message
with:
channel: "engineering-leadership"
text: "SLO Report ({{time_window}}): {{get-slo-status.at_risk_count}} SLOs at risk for {{service_tag}}."
consumes:
- type: http
namespace: datadog
baseUri: "https://api.datadoghq.com/api/v1"
authentication:
type: apikey
key: "DD-API-KEY"
value: "$secrets.datadog_api_key"
placement: header
resources:
- name: slos
path: "/slo"
inputParameters:
- name: tags
in: query
- name: time_window
in: query
operations:
- name: list-slos
method: GET
- type: http
namespace: snowflake
baseUri: "https://elsevier.snowflakecomputing.com/api/v2"
authentication:
type: bearer
token: "$secrets.snowflake_token"
resources:
- name: slo-table
path: "/statements"
operations:
- name: insert-slo-row
method: POST
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/engineering/channels/leadership/messages"
operations:
- name: send-message
method: POST
Retrieves the status of a DocuSign publishing agreement envelope, returning signer status and completion date.
naftiko: "0.5"
info:
label: "DocuSign Publishing Agreement Status"
description: "Retrieves the status of a DocuSign publishing agreement envelope, returning signer status and completion date."
tags:
- legal
- publishing
- docusign
capability:
exposes:
- type: mcp
namespace: legal-ops
port: 8080
tools:
- name: get-agreement-status
description: "Given a DocuSign envelope ID, return status and signer progress."
inputParameters:
- name: envelope_id
in: body
type: string
description: "DocuSign envelope ID."
call: docusign.get-envelope
with:
envelope_id: "{{envelope_id}}"
outputParameters:
- name: status
type: string
mapping: "$.status"
- name: completed_date
type: string
mapping: "$.completedDateTime"
consumes:
- type: http
namespace: docusign
baseUri: "https://na4.docusign.net/restapi/v2.1/accounts/$secrets.docusign_account_id"
authentication:
type: bearer
token: "$secrets.docusign_token"
resources:
- name: envelopes
path: "/envelopes/{{envelope_id}}"
inputParameters:
- name: envelope_id
in: path
operations:
- name: get-envelope
method: GET
Searches the article index in Elasticsearch by keyword, author, or DOI.
naftiko: "0.5"
info:
label: "Elasticsearch Article Search"
description: "Searches the article index in Elasticsearch by keyword, author, or DOI."
tags:
- publishing
- search
- elasticsearch
capability:
exposes:
- type: mcp
namespace: content-ops
port: 8080
tools:
- name: search-articles
description: "Given a search query, search the Elasticsearch article index."
inputParameters:
- name: query
in: body
type: string
description: "Search query (keyword, author, or DOI)."
call: elasticsearch.search
with:
index: "articles"
q: "{{query}}"
outputParameters:
- name: hits
type: array
mapping: "$.hits.hits[*]._source"
- name: total
type: integer
mapping: "$.hits.total.value"
consumes:
- type: http
namespace: elasticsearch
baseUri: "https://elsevier-es.eu-west-1.es.amazonaws.com"
authentication:
type: aws-sigv4
accessKeyId: "$secrets.aws_access_key"
secretAccessKey: "$secrets.aws_secret_key"
resources:
- name: search
path: "/articles/_search"
operations:
- name: search
method: POST
When an employee termination is processed in Workday, disables the Microsoft 365 account, revokes GitHub organization access, and opens a ServiceNow offboarding ticket.
naftiko: "0.5"
info:
label: "Employee Offboarding"
description: "When an employee termination is processed in Workday, disables the Microsoft 365 account, revokes GitHub organization access, and opens a ServiceNow offboarding ticket."
tags:
- hr
- offboarding
- workday
- microsoft-365
- github
- servicenow
- identity
capability:
exposes:
- type: mcp
namespace: hr-offboarding
port: 8080
tools:
- name: trigger-employee-offboarding
description: "Given a Workday employee ID and termination date, disable the Microsoft 365 account, remove GitHub org membership, and create a ServiceNow offboarding ticket. Use on confirmed HR termination events."
inputParameters:
- name: workday_employee_id
in: body
type: string
description: "Workday worker ID of the departing employee."
- name: termination_date
in: body
type: string
description: "Effective termination date in ISO 8601 format (YYYY-MM-DD)."
steps:
- name: get-worker
type: call
call: workday.get-worker
with:
worker_id: "{{workday_employee_id}}"
- name: disable-m365-account
type: call
call: msgraph.disable-user
with:
user_id: "{{get-worker.email}}"
accountEnabled: "false"
- name: remove-github-membership
type: call
call: github.remove-org-member
with:
org: "elsevier"
username: "{{get-worker.github_username}}"
- name: open-offboarding-ticket
type: call
call: servicenow.create-incident
with:
short_description: "Offboarding: {{get-worker.full_name}} — {{termination_date}}"
category: "offboarding"
assignment_group: "IT_Security"
consumes:
- type: http
namespace: workday
baseUri: "https://wd2-impl-services1.workday.com/ccx/api/v1"
authentication:
type: bearer
token: "$secrets.workday_token"
resources:
- name: workers
path: "/workers/{{worker_id}}"
inputParameters:
- name: worker_id
in: path
operations:
- name: get-worker
method: GET
- type: http
namespace: msgraph
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msgraph_token"
resources:
- name: users
path: "/users/{{user_id}}"
inputParameters:
- name: user_id
in: path
operations:
- name: disable-user
method: PATCH
- type: http
namespace: github
baseUri: "https://api.github.com"
authentication:
type: bearer
token: "$secrets.github_token"
resources:
- name: org-members
path: "/orgs/{{org}}/members/{{username}}"
inputParameters:
- name: org
in: path
- name: username
in: path
operations:
- name: remove-org-member
method: DELETE
- type: http
namespace: servicenow
baseUri: "https://elsevier.service-now.com/api/now"
authentication:
type: basic
username: "$secrets.servicenow_user"
password: "$secrets.servicenow_password"
resources:
- name: incidents
path: "/table/incident"
operations:
- name: create-incident
method: POST
When a journal cover design is updated in Figma, posts a review request to the editorial Microsoft Teams channel.
naftiko: "0.5"
info:
label: "Figma Cover Design Review"
description: "When a journal cover design is updated in Figma, posts a review request to the editorial Microsoft Teams channel."
tags:
- design
- publishing
- figma
- microsoft-teams
capability:
exposes:
- type: mcp
namespace: design-ops
port: 8080
tools:
- name: request-cover-review
description: "Given a Figma file key, fetch file info and post a review request to Teams."
inputParameters:
- name: file_key
in: body
type: string
description: "Figma file key."
steps:
- name: get-file
type: call
call: figma.get-file
with:
file_key: "{{file_key}}"
- name: post-review
type: call
call: msteams.post-channel-message
with:
channel_id: "editorial-design"
text: "Cover design review: {{get-file.name}} — https://www.figma.com/file/{{file_key}}"
consumes:
- type: http
namespace: figma
baseUri: "https://api.figma.com/v1"
authentication:
type: bearer
token: "$secrets.figma_token"
resources:
- name: files
path: "/files/{{file_key}}"
inputParameters:
- name: file_key
in: path
operations:
- name: get-file
method: GET
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/{{team_id}}/channels/{{channel_id}}/messages"
inputParameters:
- name: channel_id
in: path
operations:
- name: post-channel-message
method: POST
Triggers a GitHub Actions workflow and notifies the engineering Slack channel.
naftiko: "0.5"
info:
label: "GitHub Actions Pipeline Trigger"
description: "Triggers a GitHub Actions workflow and notifies the engineering Slack channel."
tags:
- engineering
- cicd
- github-actions
- slack
capability:
exposes:
- type: mcp
namespace: cicd-ops
port: 8080
tools:
- name: trigger-workflow
description: "Given a repo and workflow file, trigger a workflow dispatch and notify Slack."
inputParameters:
- name: repo
in: body
type: string
description: "GitHub repo in org/repo format."
- name: workflow_id
in: body
type: string
description: "Workflow file name."
- name: ref
in: body
type: string
description: "Git ref."
steps:
- name: dispatch
type: call
call: github.create-workflow-dispatch
with:
repo: "{{repo}}"
workflow_id: "{{workflow_id}}"
ref: "{{ref}}"
- name: notify
type: call
call: slack.post-message
with:
channel: "engineering"
text: "Workflow {{workflow_id}} triggered on {{repo}} ({{ref}})"
consumes:
- type: http
namespace: github
baseUri: "https://api.github.com"
authentication:
type: bearer
token: "$secrets.github_token"
resources:
- name: dispatches
path: "/repos/{{repo}}/actions/workflows/{{workflow_id}}/dispatches"
inputParameters:
- name: repo
in: path
- name: workflow_id
in: path
operations:
- name: create-workflow-dispatch
method: POST
- type: http
namespace: slack
baseUri: "https://slack.com/api"
authentication:
type: bearer
token: "$secrets.slack_bot_token"
resources:
- name: messages
path: "/chat.postMessage"
operations:
- name: post-message
method: POST
Checks whether a GitHub repository meets code review policies including branch protection and CODEOWNERS, posting results to Slack.
naftiko: "0.5"
info:
label: "GitHub Code Review Policy Check"
description: "Checks whether a GitHub repository meets code review policies including branch protection and CODEOWNERS, posting results to Slack."
tags:
- engineering
- compliance
- github
- slack
capability:
exposes:
- type: mcp
namespace: eng-compliance
port: 8080
tools:
- name: check-review-policy
description: "Given a GitHub repository, verify branch protection and CODEOWNERS presence, then post compliance status to Slack."
inputParameters:
- name: repo
in: body
type: string
description: "GitHub repository in org/repo format."
steps:
- name: get-protection
type: call
call: github.get-branch-protection
with:
repo: "{{repo}}"
branch: "main"
- name: post-status
type: call
call: slack.post-message
with:
channel: "engineering-compliance"
text: "Repo compliance check for {{repo}}: branch protection={{get-protection.enabled}}"
consumes:
- type: http
namespace: github
baseUri: "https://api.github.com"
authentication:
type: bearer
token: "$secrets.github_token"
resources:
- name: branch-protection
path: "/repos/{{repo}}/branches/{{branch}}/protection"
inputParameters:
- name: repo
in: path
- name: branch
in: path
operations:
- name: get-branch-protection
method: GET
- type: http
namespace: slack
baseUri: "https://slack.com/api"
authentication:
type: bearer
token: "$secrets.slack_bot_token"
resources:
- name: messages
path: "/chat.postMessage"
operations:
- name: post-message
method: POST
On a pull request to a main branch in GitHub, triggers a code quality scan, posts results as a PR comment, and blocks merge if quality thresholds are not met.
naftiko: "0.5"
info:
label: "GitHub Pull Request Quality Gate"
description: "On a pull request to a main branch in GitHub, triggers a code quality scan, posts results as a PR comment, and blocks merge if quality thresholds are not met."
tags:
- devops
- github
- code-quality
- ci-cd
capability:
exposes:
- type: mcp
namespace: devops-quality
port: 8080
tools:
- name: run-pr-quality-gate
description: "Given a GitHub repository name, PR number, and commit SHA, fetch PR metadata, post a status check result, and add a summary comment. Use as part of the CI/CD quality enforcement pipeline."
inputParameters:
- name: repo_full_name
in: body
type: string
description: "GitHub repository full name (e.g., elsevier/sciencedirect-api)."
- name: pr_number
in: body
type: integer
description: "Pull request number."
- name: commit_sha
in: body
type: string
description: "Head commit SHA for the pull request."
- name: quality_score
in: body
type: number
description: "Code quality score from 0 to 100 from the upstream scanner."
steps:
- name: get-pr
type: call
call: github.get-pull-request
with:
repo: "{{repo_full_name}}"
pull_number: "{{pr_number}}"
- name: post-status
type: call
call: github-status.create-commit-status
with:
repo: "{{repo_full_name}}"
sha: "{{commit_sha}}"
state: "success"
description: "Quality score: {{quality_score}}/100"
context: "naftiko/quality-gate"
- name: post-comment
type: call
call: github-comment.create-issue-comment
with:
repo: "{{repo_full_name}}"
issue_number: "{{pr_number}}"
body: "Quality Gate Result: {{quality_score}}/100 — {{get-pr.title}}"
consumes:
- type: http
namespace: github
baseUri: "https://api.github.com"
authentication:
type: bearer
token: "$secrets.github_token"
resources:
- name: pull-requests
path: "/repos/{{repo}}/pulls/{{pull_number}}"
inputParameters:
- name: repo
in: path
- name: pull_number
in: path
operations:
- name: get-pull-request
method: GET
- type: http
namespace: github-status
baseUri: "https://api.github.com"
authentication:
type: bearer
token: "$secrets.github_token"
resources:
- name: commit-statuses
path: "/repos/{{repo}}/statuses/{{sha}}"
inputParameters:
- name: repo
in: path
- name: sha
in: path
operations:
- name: create-commit-status
method: POST
- type: http
namespace: github-comment
baseUri: "https://api.github.com"
authentication:
type: bearer
token: "$secrets.github_token"
resources:
- name: issue-comments
path: "/repos/{{repo}}/issues/{{issue_number}}/comments"
inputParameters:
- name: repo
in: path
- name: issue_number
in: path
operations:
- name: create-issue-comment
method: POST
Fetches open Dependabot alerts for a repository and posts the severity summary to the security Microsoft Teams channel.
naftiko: "0.5"
info:
label: "GitHub Security Vulnerability Scan"
description: "Fetches open Dependabot alerts for a repository and posts the severity summary to the security Microsoft Teams channel."
tags:
- security
- engineering
- github
- microsoft-teams
capability:
exposes:
- type: mcp
namespace: appsec
port: 8080
tools:
- name: scan-vulnerabilities
description: "Given a GitHub repo, fetch open security alerts and post a summary to the security Teams channel."
inputParameters:
- name: repo
in: body
type: string
description: "GitHub repo in org/repo format."
steps:
- name: get-alerts
type: call
call: github.list-dependabot-alerts
with:
repo: "{{repo}}"
state: "open"
- name: post-summary
type: call
call: msteams.post-channel-message
with:
channel_id: "security-alerts"
text: "Security scan for {{repo}}: {{get-alerts.total}} open vulnerabilities"
consumes:
- type: http
namespace: github
baseUri: "https://api.github.com"
authentication:
type: bearer
token: "$secrets.github_token"
resources:
- name: dependabot-alerts
path: "/repos/{{repo}}/dependabot/alerts"
inputParameters:
- name: repo
in: path
operations:
- name: list-dependabot-alerts
method: GET
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/{{team_id}}/channels/{{channel_id}}/messages"
inputParameters:
- name: channel_id
in: path
operations:
- name: post-channel-message
method: POST
Scans GitHub Dependabot alerts for critical vulnerabilities across Elsevier repositories, creates Jira security issues for each, and notifies the security team via Teams.
naftiko: "0.5"
info:
label: "GitHub Security Vulnerability Triage"
description: "Scans GitHub Dependabot alerts for critical vulnerabilities across Elsevier repositories, creates Jira security issues for each, and notifies the security team via Teams."
tags:
- security
- devops
- github
- jira
- msteams
- vulnerability-management
capability:
exposes:
- type: mcp
namespace: security-triage
port: 8080
tools:
- name: triage-dependabot-alerts
description: "Given a GitHub organization name and severity filter, list open Dependabot vulnerability alerts, create a Jira security issue for each critical finding, and post a summary to the security Teams channel."
inputParameters:
- name: github_org
in: body
type: string
description: "GitHub organization name to scan (e.g., elsevier)."
- name: severity
in: body
type: string
description: "Minimum severity to triage: critical, high, medium, or low."
steps:
- name: list-alerts
type: call
call: github.list-org-dependabot-alerts
with:
org: "{{github_org}}"
severity: "{{severity}}"
- name: create-security-issue
type: call
call: jira.create-issue
with:
project_key: "SEC"
issuetype: "Security Vulnerability"
summary: "[{{severity}}] Dependabot alerts in {{github_org}}: {{list-alerts.alert_count}} findings"
description: "Repositories affected: {{list-alerts.repo_names}}. Packages: {{list-alerts.package_names}}"
- name: notify-security-team
type: call
call: msteams.send-message
with:
channel: "security-ops"
text: "Dependabot triage: {{list-alerts.alert_count}} {{severity}} alerts in {{github_org}}. Jira: {{create-security-issue.key}}"
consumes:
- type: http
namespace: github
baseUri: "https://api.github.com"
authentication:
type: bearer
token: "$secrets.github_token"
resources:
- name: dependabot-alerts
path: "/orgs/{{org}}/dependabot/alerts"
inputParameters:
- name: org
in: path
- name: severity
in: query
operations:
- name: list-org-dependabot-alerts
method: GET
- type: http
namespace: jira
baseUri: "https://elsevier.atlassian.net/rest/api/3"
authentication:
type: basic
username: "$secrets.jira_user"
password: "$secrets.jira_api_token"
resources:
- name: issues
path: "/issue"
operations:
- name: create-issue
method: POST
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/security/channels/ops/messages"
operations:
- name: send-message
method: POST
Retrieves weekly content usage metrics from Google Analytics for a property and posts to Microsoft Teams.
naftiko: "0.5"
info:
label: "Google Analytics Content Usage"
description: "Retrieves weekly content usage metrics from Google Analytics for a property and posts to Microsoft Teams."
tags:
- analytics
- publishing
- google-analytics
- microsoft-teams
capability:
exposes:
- type: mcp
namespace: content-analytics
port: 8080
tools:
- name: post-usage-report
description: "Fetch weekly usage metrics from Google Analytics and post to Teams."
inputParameters:
- name: property_id
in: body
type: string
description: "Google Analytics property ID."
steps:
- name: get-report
type: call
call: ga.run-report
with:
property_id: "{{property_id}}"
date_range: "last7days"
- name: post-teams
type: call
call: msteams.post-channel-message
with:
channel_id: "content-analytics"
text: "Weekly content usage: {{get-report.sessions}} sessions, {{get-report.users}} users"
consumes:
- type: http
namespace: ga
baseUri: "https://analyticsdata.googleapis.com/v1beta"
authentication:
type: bearer
token: "$secrets.google_analytics_token"
resources:
- name: reports
path: "/properties/{{property_id}}:runReport"
inputParameters:
- name: property_id
in: path
operations:
- name: run-report
method: POST
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/{{team_id}}/channels/{{channel_id}}/messages"
inputParameters:
- name: channel_id
in: path
operations:
- name: post-channel-message
method: POST
Uploads an editorial file to Google Drive and shares the link with the author via email.
naftiko: "0.5"
info:
label: "Google Drive Editorial File Share"
description: "Uploads an editorial file to Google Drive and shares the link with the author via email."
tags:
- publishing
- collaboration
- google-drive
- sendgrid
capability:
exposes:
- type: mcp
namespace: editorial-ops
port: 8080
tools:
- name: share-editorial-file
description: "Upload a file to Google Drive and email the share link to the author."
inputParameters:
- name: file_name
in: body
type: string
description: "File name."
- name: folder_id
in: body
type: string
description: "Google Drive folder ID."
- name: author_email
in: body
type: string
description: "Author email."
steps:
- name: upload-file
type: call
call: gdrive.upload-file
with:
folder_id: "{{folder_id}}"
name: "{{file_name}}"
- name: email-author
type: call
call: sendgrid.send-email
with:
to: "{{author_email}}"
subject: "Your editorial file is ready"
content: "Download your file: {{upload-file.webViewLink}}"
consumes:
- type: http
namespace: gdrive
baseUri: "https://www.googleapis.com/upload/drive/v3"
authentication:
type: bearer
token: "$secrets.google_drive_token"
resources:
- name: files
path: "/files"
operations:
- name: upload-file
method: POST
- type: http
namespace: sendgrid
baseUri: "https://api.sendgrid.com/v3"
authentication:
type: bearer
token: "$secrets.sendgrid_api_key"
resources:
- name: mail
path: "/mail/send"
operations:
- name: send-email
method: POST
Retrieves the current state of a Grafana alert rule monitoring content delivery performance.
naftiko: "0.5"
info:
label: "Grafana Content Delivery Dashboard"
description: "Retrieves the current state of a Grafana alert rule monitoring content delivery performance."
tags:
- monitoring
- publishing
- grafana
capability:
exposes:
- type: mcp
namespace: observability
port: 8080
tools:
- name: get-delivery-alert-status
description: "Given a Grafana alert rule UID, return its current firing state."
inputParameters:
- name: rule_uid
in: body
type: string
description: "Grafana alert rule UID."
call: grafana.get-alert-rule
with:
uid: "{{rule_uid}}"
outputParameters:
- name: state
type: string
mapping: "$.state"
consumes:
- type: http
namespace: grafana
baseUri: "https://grafana.elsevier.com/api"
authentication:
type: bearer
token: "$secrets.grafana_token"
resources:
- name: alert-rules
path: "/v1/provisioning/alert-rules/{{uid}}"
inputParameters:
- name: uid
in: path
operations:
- name: get-alert-rule
method: GET
Fetches author data from Salesforce and upserts into HubSpot for marketing engagement.
naftiko: "0.5"
info:
label: "HubSpot Author Contact Sync"
description: "Fetches author data from Salesforce and upserts into HubSpot for marketing engagement."
tags:
- marketing
- crm
- hubspot
- salesforce
capability:
exposes:
- type: mcp
namespace: marketing-ops
port: 8080
tools:
- name: sync-author-to-hubspot
description: "Given a Salesforce contact ID, fetch author data and upsert into HubSpot."
inputParameters:
- name: contact_id
in: body
type: string
description: "Salesforce contact ID."
steps:
- name: get-sf-contact
type: call
call: salesforce.get-contact
with:
contact_id: "{{contact_id}}"
- name: upsert-hubspot
type: call
call: hubspot.upsert-contact
with:
email: "{{get-sf-contact.Email}}"
properties:
firstname: "{{get-sf-contact.FirstName}}"
lastname: "{{get-sf-contact.LastName}}"
consumes:
- type: http
namespace: salesforce
baseUri: "https://elsevier.my.salesforce.com/services/data/v58.0"
authentication:
type: bearer
token: "$secrets.salesforce_token"
resources:
- name: contacts
path: "/sobjects/Contact/{{contact_id}}"
inputParameters:
- name: contact_id
in: path
operations:
- name: get-contact
method: GET
- type: http
namespace: hubspot
baseUri: "https://api.hubapi.com"
authentication:
type: bearer
token: "$secrets.hubspot_token"
resources:
- name: contacts
path: "/crm/v3/objects/contacts"
operations:
- name: upsert-contact
method: POST
Fetches HubSpot email campaign performance metrics, writes them to Snowflake, and triggers a Power BI refresh for the marketing leadership dashboard.
naftiko: "0.5"
info:
label: "HubSpot Campaign Performance Report"
description: "Fetches HubSpot email campaign performance metrics, writes them to Snowflake, and triggers a Power BI refresh for the marketing leadership dashboard."
tags:
- marketing
- reporting
- hubspot
- snowflake
- power-bi
capability:
exposes:
- type: mcp
namespace: campaign-reporting
port: 8080
tools:
- name: report-campaign-performance
description: "Given a HubSpot campaign ID, fetch email open, click, and unsubscribe rates, write the metrics to Snowflake, and trigger a Power BI marketing dashboard refresh. Use after campaign completion."
inputParameters:
- name: hubspot_campaign_id
in: body
type: string
description: "HubSpot email campaign ID to report on."
steps:
- name: get-campaign-stats
type: call
call: hubspot.get-campaign-stats
with:
campaign_id: "{{hubspot_campaign_id}}"
- name: write-metrics
type: call
call: snowflake.insert-campaign-row
with:
campaign_id: "{{hubspot_campaign_id}}"
open_rate: "{{get-campaign-stats.open_rate}}"
click_rate: "{{get-campaign-stats.click_rate}}"
unsubscribe_rate: "{{get-campaign-stats.unsubscribe_rate}}"
- name: refresh-dashboard
type: call
call: powerbi.trigger-refresh
with:
dataset_id: "$secrets.powerbi_marketing_dataset_id"
consumes:
- type: http
namespace: hubspot
baseUri: "https://api.hubapi.com/marketing/v3"
authentication:
type: bearer
token: "$secrets.hubspot_token"
resources:
- name: campaign-stats
path: "/emails/statistics/list"
inputParameters:
- name: campaign_id
in: query
operations:
- name: get-campaign-stats
method: GET
- type: http
namespace: snowflake
baseUri: "https://elsevier.snowflakecomputing.com/api/v2"
authentication:
type: bearer
token: "$secrets.snowflake_token"
resources:
- name: campaign-metrics
path: "/statements"
operations:
- name: insert-campaign-row
method: POST
- type: http
namespace: powerbi
baseUri: "https://api.powerbi.com/v1.0/myorg"
authentication:
type: bearer
token: "$secrets.powerbi_token"
resources:
- name: dataset-refreshes
path: "/datasets/{{dataset_id}}/refreshes"
inputParameters:
- name: dataset_id
in: path
operations:
- name: trigger-refresh
method: POST
When a new HubSpot contact is created from a trial form, enriches the record with Scopus publication count and research area, then updates the contact properties.
naftiko: "0.5"
info:
label: "HubSpot Lead Enrichment from Scopus"
description: "When a new HubSpot contact is created from a trial form, enriches the record with Scopus publication count and research area, then updates the contact properties."
tags:
- marketing
- crm
- data-enrichment
- hubspot
- scopus
capability:
exposes:
- type: mcp
namespace: marketing-enrichment
port: 8080
tools:
- name: enrich-hubspot-lead
description: "Given a HubSpot contact ID and the contact's email, search Scopus for their author profile, then update the HubSpot contact with publication count and primary subject area. Use for trial lead scoring."
inputParameters:
- name: hubspot_contact_id
in: body
type: string
description: "HubSpot contact ID for the trial signup."
- name: author_email
in: body
type: string
description: "Author email address to search in Scopus."
steps:
- name: search-scopus-author
type: call
call: scopus.search-author-by-email
with:
email: "{{author_email}}"
- name: update-contact
type: call
call: hubspot.patch-contact
with:
contact_id: "{{hubspot_contact_id}}"
publication_count: "{{search-scopus-author.document_count}}"
primary_subject_area: "{{search-scopus-author.subject_area}}"
h_index: "{{search-scopus-author.h_index}}"
consumes:
- type: http
namespace: scopus
baseUri: "https://api.elsevier.com/content/search/author"
authentication:
type: apikey
key: "X-ELS-APIKey"
value: "$secrets.scopus_api_key"
placement: header
resources:
- name: author-search
path: "/"
inputParameters:
- name: email
in: query
operations:
- name: search-author-by-email
method: GET
- type: http
namespace: hubspot
baseUri: "https://api.hubapi.com/crm/v3"
authentication:
type: bearer
token: "$secrets.hubspot_token"
resources:
- name: contacts
path: "/objects/contacts/{{contact_id}}"
inputParameters:
- name: contact_id
in: path
operations:
- name: patch-contact
method: PATCH
Creates a Jira ticket in the editorial workflow project and notifies the editorial team via Microsoft Teams.
naftiko: "0.5"
info:
label: "Jira Editorial Ticket Creation"
description: "Creates a Jira ticket in the editorial workflow project and notifies the editorial team via Microsoft Teams."
tags:
- publishing
- editorial
- jira
- microsoft-teams
capability:
exposes:
- type: mcp
namespace: editorial-ops
port: 8080
tools:
- name: create-editorial-ticket
description: "Given a manuscript ID and issue type, create a Jira editorial ticket and notify the Teams editorial channel."
inputParameters:
- name: manuscript_id
in: body
type: string
description: "Manuscript submission ID."
- name: issue_type
in: body
type: string
description: "Issue type (Revision, Proof, Correction)."
- name: summary
in: body
type: string
description: "Ticket summary."
steps:
- name: create-ticket
type: call
call: jira.create-issue
with:
project_key: "EDIT"
issuetype: "{{issue_type}}"
summary: "{{summary}}"
description: "Manuscript: {{manuscript_id}}"
- name: notify-editorial
type: call
call: msteams.post-channel-message
with:
channel_id: "editorial-workflow"
text: "Editorial ticket created: {{create-ticket.key}} — {{summary}} (Manuscript: {{manuscript_id}})"
consumes:
- type: http
namespace: jira
baseUri: "https://elsevier.atlassian.net/rest/api/3"
authentication:
type: basic
username: "$secrets.jira_user"
password: "$secrets.jira_token"
resources:
- name: issues
path: "/issue"
operations:
- name: create-issue
method: POST
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/{{team_id}}/channels/{{channel_id}}/messages"
inputParameters:
- name: channel_id
in: path
operations:
- name: post-channel-message
method: POST
Searches Jira for overdue tickets and posts the count to a Microsoft Teams channel.
naftiko: "0.5"
info:
label: "Jira Overdue Ticket Report"
description: "Searches Jira for overdue tickets and posts the count to a Microsoft Teams channel."
tags:
- project-management
- engineering
- jira
- microsoft-teams
capability:
exposes:
- type: mcp
namespace: eng-ops
port: 8080
tools:
- name: report-overdue-tickets
description: "Search Jira for overdue tickets in a project and post the count to Teams."
inputParameters:
- name: project_key
in: body
type: string
description: "Jira project key."
steps:
- name: search-overdue
type: call
call: jira.search-issues
with:
jql: "project={{project_key}} AND duedate < now() AND status != Done"
- name: post-report
type: call
call: msteams.post-channel-message
with:
channel_id: "engineering"
text: "Overdue tickets in {{project_key}}: {{search-overdue.total}} issues"
consumes:
- type: http
namespace: jira
baseUri: "https://elsevier.atlassian.net/rest/api/3"
authentication:
type: basic
username: "$secrets.jira_user"
password: "$secrets.jira_token"
resources:
- name: search
path: "/search"
operations:
- name: search-issues
method: POST
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/{{team_id}}/channels/{{channel_id}}/messages"
inputParameters:
- name: channel_id
in: path
operations:
- name: post-channel-message
method: POST
Fetches resolved Jira issues for a version and creates a Confluence release notes page.
naftiko: "0.5"
info:
label: "Jira Release Notes Creation"
description: "Fetches resolved Jira issues for a version and creates a Confluence release notes page."
tags:
- engineering
- release-management
- jira
- confluence
capability:
exposes:
- type: mcp
namespace: release-ops
port: 8080
tools:
- name: create-release-notes
description: "Given a Jira project and version, create Confluence release notes."
inputParameters:
- name: project_key
in: body
type: string
description: "Jira project key."
- name: version
in: body
type: string
description: "Fix version name."
steps:
- name: get-issues
type: call
call: jira.search-issues
with:
jql: "project={{project_key}} AND fixVersion='{{version}}' AND status=Done"
- name: create-page
type: call
call: confluence.create-content
with:
space_key: "RELEASES"
title: "Release Notes — {{version}}"
body: "{{get-issues.formatted}}"
consumes:
- type: http
namespace: jira
baseUri: "https://elsevier.atlassian.net/rest/api/3"
authentication:
type: basic
username: "$secrets.jira_user"
password: "$secrets.jira_token"
resources:
- name: search
path: "/search"
operations:
- name: search-issues
method: POST
- type: http
namespace: confluence
baseUri: "https://elsevier.atlassian.net/wiki/rest/api"
authentication:
type: basic
username: "$secrets.confluence_user"
password: "$secrets.confluence_token"
resources:
- name: content
path: "/content"
operations:
- name: create-content
method: POST
Fetches completed sprint data from Jira, calculates velocity metrics, writes results to Snowflake, and publishes a Power BI report refresh for engineering leadership.
naftiko: "0.5"
info:
label: "Jira Sprint Velocity Report"
description: "Fetches completed sprint data from Jira, calculates velocity metrics, writes results to Snowflake, and publishes a Power BI report refresh for engineering leadership."
tags:
- devops
- reporting
- jira
- snowflake
- power-bi
- agile
capability:
exposes:
- type: mcp
namespace: engineering-reporting
port: 8080
tools:
- name: publish-sprint-velocity
description: "Given a Jira project key and sprint ID, fetch story points completed, write the velocity data to Snowflake, and trigger a Power BI refresh. Use after each sprint retrospective."
inputParameters:
- name: jira_project_key
in: body
type: string
description: "Jira project key (e.g., PLAT, API)."
- name: sprint_id
in: body
type: integer
description: "Jira sprint ID to report on."
steps:
- name: get-sprint-report
type: call
call: jira.get-sprint
with:
sprint_id: "{{sprint_id}}"
- name: write-velocity
type: call
call: snowflake.insert-velocity-row
with:
project_key: "{{jira_project_key}}"
sprint_id: "{{sprint_id}}"
completed_points: "{{get-sprint-report.completedPoints}}"
- name: refresh-report
type: call
call: powerbi.trigger-refresh
with:
dataset_id: "$secrets.powerbi_velocity_dataset_id"
consumes:
- type: http
namespace: jira
baseUri: "https://elsevier.atlassian.net/rest/api/3"
authentication:
type: basic
username: "$secrets.jira_user"
password: "$secrets.jira_api_token"
resources:
- name: sprints
path: "/sprint/{{sprint_id}}"
inputParameters:
- name: sprint_id
in: path
operations:
- name: get-sprint
method: GET
- type: http
namespace: snowflake
baseUri: "https://elsevier.snowflakecomputing.com/api/v2"
authentication:
type: bearer
token: "$secrets.snowflake_token"
resources:
- name: velocity-table
path: "/statements"
operations:
- name: insert-velocity-row
method: POST
- type: http
namespace: powerbi
baseUri: "https://api.powerbi.com/v1.0/myorg"
authentication:
type: bearer
token: "$secrets.powerbi_token"
resources:
- name: dataset-refreshes
path: "/datasets/{{dataset_id}}/refreshes"
inputParameters:
- name: dataset_id
in: path
operations:
- name: trigger-refresh
method: POST
Pulls citation data from Scopus and article download metrics from the content platform, aggregates them in Snowflake, and publishes a Power BI dashboard refresh for editorial leadership.
naftiko: "0.5"
info:
label: "Journal Impact Factor Report"
description: "Pulls citation data from Scopus and article download metrics from the content platform, aggregates them in Snowflake, and publishes a Power BI dashboard refresh for editorial leadership."
tags:
- publishing
- analytics
- reporting
- scopus
- snowflake
- power-bi
capability:
exposes:
- type: mcp
namespace: journal-reporting
port: 8080
tools:
- name: refresh-impact-report
description: "Given a journal ISSN and reporting year, fetch citation counts from Scopus, write a summary row to Snowflake, and trigger a Power BI dataset refresh. Use for monthly editorial KPI reporting."
inputParameters:
- name: journal_issn
in: body
type: string
description: "Journal ISSN (e.g., 0140-6736)."
- name: report_year
in: body
type: integer
description: "Four-digit reporting year (e.g., 2025)."
steps:
- name: get-citations
type: call
call: scopus.get-journal-citations
with:
issn: "{{journal_issn}}"
year: "{{report_year}}"
- name: write-snowflake
type: call
call: snowflake.insert-impact-row
with:
issn: "{{journal_issn}}"
year: "{{report_year}}"
citation_count: "{{get-citations.citation_count}}"
impact_factor: "{{get-citations.impact_factor}}"
- name: refresh-dataset
type: call
call: powerbi.trigger-refresh
with:
dataset_id: "$secrets.powerbi_journal_dataset_id"
consumes:
- type: http
namespace: scopus
baseUri: "https://api.elsevier.com/content/serial/title"
authentication:
type: apikey
key: "X-ELS-APIKey"
value: "$secrets.scopus_api_key"
placement: header
resources:
- name: journal-metrics
path: "/issn/{{issn}}"
inputParameters:
- name: issn
in: path
- name: year
in: query
operations:
- name: get-journal-citations
method: GET
- type: http
namespace: snowflake
baseUri: "https://elsevier.snowflakecomputing.com/api/v2"
authentication:
type: bearer
token: "$secrets.snowflake_token"
resources:
- name: impact-table
path: "/statements"
operations:
- name: insert-impact-row
method: POST
- type: http
namespace: powerbi
baseUri: "https://api.powerbi.com/v1.0/myorg"
authentication:
type: bearer
token: "$secrets.powerbi_token"
resources:
- name: dataset-refresh
path: "/datasets/{{dataset_id}}/refreshes"
inputParameters:
- name: dataset_id
in: path
operations:
- name: trigger-refresh
method: POST
Checks Kubernetes pod status via Datadog and alerts the platform Slack channel if pods are unhealthy.
naftiko: "0.5"
info:
label: "Kubernetes Pod Health Check"
description: "Checks Kubernetes pod status via Datadog and alerts the platform Slack channel if pods are unhealthy."
tags:
- infrastructure
- containers
- kubernetes
- datadog
- slack
capability:
exposes:
- type: mcp
namespace: platform-ops
port: 8080
tools:
- name: check-pod-health
description: "Given a Kubernetes namespace and deployment, check pod health via Datadog and alert Slack."
inputParameters:
- name: namespace
in: body
type: string
description: "Kubernetes namespace."
- name: deployment
in: body
type: string
description: "Deployment name."
steps:
- name: query-health
type: call
call: datadog.query-timeseries
with:
query: "avg:kubernetes.pods.running{kube_namespace:{{namespace}},kube_deployment:{{deployment}}}"
- name: alert-if-unhealthy
type: call
call: slack.post-message
with:
channel: "platform-ops"
text: "Pod health for {{namespace}}/{{deployment}}: {{query-health.series[0].pointlist[-1][1]}} running pods"
consumes:
- type: http
namespace: datadog
baseUri: "https://api.datadoghq.com/api/v1"
authentication:
type: apikey
key: "DD-API-KEY"
value: "$secrets.datadog_api_key"
placement: header
resources:
- name: query
path: "/query"
operations:
- name: query-timeseries
method: GET
- type: http
namespace: slack
baseUri: "https://slack.com/api"
authentication:
type: bearer
token: "$secrets.slack_bot_token"
resources:
- name: messages
path: "/chat.postMessage"
operations:
- name: post-message
method: POST
Fetches Elsevier LinkedIn page post engagement metrics, aggregates them in Snowflake, and sends a weekly performance digest to the social media team via Teams.
naftiko: "0.5"
info:
label: "LinkedIn Content Performance Digest"
description: "Fetches Elsevier LinkedIn page post engagement metrics, aggregates them in Snowflake, and sends a weekly performance digest to the social media team via Teams."
tags:
- marketing
- social
- linkedin
- snowflake
- msteams
- reporting
capability:
exposes:
- type: mcp
namespace: social-reporting
port: 8080
tools:
- name: digest-linkedin-performance
description: "Given a LinkedIn organization ID and a date range, fetch post engagement stats, write aggregates to Snowflake, and send a Teams digest to the social media channel. Use for weekly social performance reviews."
inputParameters:
- name: organization_id
in: body
type: string
description: "LinkedIn organization ID (URN) for the Elsevier company page."
- name: start_date
in: body
type: string
description: "Report start date in ISO 8601 format (YYYY-MM-DD)."
- name: end_date
in: body
type: string
description: "Report end date in ISO 8601 format (YYYY-MM-DD)."
steps:
- name: get-post-stats
type: call
call: linkedin.get-share-statistics
with:
organization_id: "{{organization_id}}"
start: "{{start_date}}"
end: "{{end_date}}"
- name: write-stats
type: call
call: snowflake.insert-social-row
with:
platform: "linkedin"
impressions: "{{get-post-stats.totalImpressions}}"
engagements: "{{get-post-stats.totalEngagements}}"
start_date: "{{start_date}}"
- name: send-digest
type: call
call: msteams.send-message
with:
channel: "social-media"
text: "LinkedIn Performance {{start_date}} to {{end_date}}: {{get-post-stats.totalImpressions}} impressions, {{get-post-stats.totalEngagements}} engagements."
consumes:
- type: http
namespace: linkedin
baseUri: "https://api.linkedin.com/v2"
authentication:
type: bearer
token: "$secrets.linkedin_token"
resources:
- name: share-statistics
path: "/organizationalEntityShareStatistics"
inputParameters:
- name: organization_id
in: query
- name: start
in: query
- name: end
in: query
operations:
- name: get-share-statistics
method: GET
- type: http
namespace: snowflake
baseUri: "https://elsevier.snowflakecomputing.com/api/v2"
authentication:
type: bearer
token: "$secrets.snowflake_token"
resources:
- name: social-stats
path: "/statements"
operations:
- name: insert-social-row
method: POST
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/marketing/channels/social/messages"
operations:
- name: send-message
method: POST
Fetches LinkedIn company page analytics and posts a weekly engagement summary to the marketing Slack channel.
naftiko: "0.5"
info:
label: "LinkedIn Thought Leadership Digest"
description: "Fetches LinkedIn company page analytics and posts a weekly engagement summary to the marketing Slack channel."
tags:
- marketing
- social-media
- linkedin
- slack
capability:
exposes:
- type: mcp
namespace: social-ops
port: 8080
tools:
- name: post-linkedin-digest
description: "Fetch LinkedIn page analytics and post a weekly digest to Slack."
inputParameters:
- name: org_id
in: body
type: string
description: "LinkedIn organization ID."
steps:
- name: get-analytics
type: call
call: linkedin.get-page-analytics
with:
organization: "{{org_id}}"
- name: post-digest
type: call
call: slack.post-message
with:
channel: "marketing-social"
text: "LinkedIn weekly digest: {{get-analytics.impressions}} impressions, {{get-analytics.engagement_rate}}% engagement"
consumes:
- type: http
namespace: linkedin
baseUri: "https://api.linkedin.com/v2"
authentication:
type: bearer
token: "$secrets.linkedin_token"
resources:
- name: analytics
path: "/organizationalEntityShareStatistics"
operations:
- name: get-page-analytics
method: GET
- type: http
namespace: slack
baseUri: "https://slack.com/api"
authentication:
type: bearer
token: "$secrets.slack_bot_token"
resources:
- name: messages
path: "/chat.postMessage"
operations:
- name: post-message
method: POST
Retrieves open rate and click rate for a Mailchimp journal newsletter campaign.
naftiko: "0.5"
info:
label: "Mailchimp Newsletter Performance"
description: "Retrieves open rate and click rate for a Mailchimp journal newsletter campaign."
tags:
- marketing
- email
- mailchimp
capability:
exposes:
- type: mcp
namespace: email-ops
port: 8080
tools:
- name: get-newsletter-stats
description: "Given a Mailchimp campaign ID, return open rate and click rate."
inputParameters:
- name: campaign_id
in: body
type: string
description: "Mailchimp campaign ID."
call: mailchimp.get-report
with:
campaign_id: "{{campaign_id}}"
outputParameters:
- name: open_rate
type: number
mapping: "$.opens.open_rate"
- name: click_rate
type: number
mapping: "$.clicks.click_rate"
consumes:
- type: http
namespace: mailchimp
baseUri: "https://us1.api.mailchimp.com/3.0"
authentication:
type: basic
username: "anystring"
password: "$secrets.mailchimp_api_key"
resources:
- name: reports
path: "/reports/{{campaign_id}}"
inputParameters:
- name: campaign_id
in: path
operations:
- name: get-report
method: GET
Submits a manuscript for plagiarism screening and posts the similarity score to the editorial Slack channel.
naftiko: "0.5"
info:
label: "Manuscript Plagiarism Check Trigger"
description: "Submits a manuscript for plagiarism screening and posts the similarity score to the editorial Slack channel."
tags:
- publishing
- editorial
- ithenticate
- slack
capability:
exposes:
- type: mcp
namespace: editorial-ops
port: 8080
tools:
- name: check-plagiarism
description: "Given a manuscript ID and document URL, submit for plagiarism screening and notify the editorial Slack channel with the similarity score."
inputParameters:
- name: manuscript_id
in: body
type: string
description: "Manuscript submission ID."
- name: document_url
in: body
type: string
description: "URL of the manuscript document."
steps:
- name: submit-check
type: call
call: ithenticate.submit-document
with:
document_url: "{{document_url}}"
title: "Manuscript {{manuscript_id}}"
- name: notify-editorial
type: call
call: slack.post-message
with:
channel: "editorial-ops"
text: "Plagiarism check submitted for manuscript {{manuscript_id}}. Submission ID: {{submit-check.id}}"
consumes:
- type: http
namespace: ithenticate
baseUri: "https://api.ithenticate.com/v2"
authentication:
type: bearer
token: "$secrets.ithenticate_token"
resources:
- name: submissions
path: "/submissions"
operations:
- name: submit-document
method: POST
- type: http
namespace: slack
baseUri: "https://slack.com/api"
authentication:
type: bearer
token: "$secrets.slack_bot_token"
resources:
- name: messages
path: "/chat.postMessage"
operations:
- name: post-message
method: POST
Retrieves Microsoft 365 license usage data via Microsoft Graph.
naftiko: "0.5"
info:
label: "Microsoft 365 License Report"
description: "Retrieves Microsoft 365 license usage data via Microsoft Graph."
tags:
- it-operations
- license-management
- microsoft-365
capability:
exposes:
- type: mcp
namespace: it-ops
port: 8080
tools:
- name: get-license-report
description: "Retrieve Microsoft 365 license usage data."
inputParameters:
- name: period
in: body
type: string
description: "Report period (D7, D30)."
call: msgraph.get-license-report
with:
period: "{{period}}"
outputParameters:
- name: data
type: array
mapping: "$.value"
consumes:
- type: http
namespace: msgraph
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msgraph_token"
resources:
- name: reports
path: "/reports/getOffice365ActiveUserDetail(period='{{period}}')"
inputParameters:
- name: period
in: path
operations:
- name: get-license-report
method: GET
Posts a journal publication alert to a Microsoft Teams channel when a new issue is published.
naftiko: "0.5"
info:
label: "Microsoft Teams Journal Alert"
description: "Posts a journal publication alert to a Microsoft Teams channel when a new issue is published."
tags:
- publishing
- communications
- microsoft-teams
capability:
exposes:
- type: mcp
namespace: publishing-ops
port: 8080
tools:
- name: post-journal-alert
description: "Given a journal name, volume, issue, and Teams channel, post a new issue publication notification."
inputParameters:
- name: journal_name
in: body
type: string
description: "Journal name."
- name: volume
in: body
type: string
description: "Volume number."
- name: issue
in: body
type: string
description: "Issue number."
- name: teams_channel_id
in: body
type: string
description: "Microsoft Teams channel ID."
call: msteams.post-channel-message
with:
channel_id: "{{teams_channel_id}}"
text: "New issue published: {{journal_name}} Vol. {{volume}} Issue {{issue}}"
outputParameters:
- name: message_id
type: string
mapping: "$.id"
consumes:
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/{{team_id}}/channels/{{channel_id}}/messages"
inputParameters:
- name: channel_id
in: path
operations:
- name: post-channel-message
method: POST
When a new hire record is created in Workday, provisions a Microsoft 365 account, opens a ServiceNow IT onboarding ticket, and sends a welcome message via Microsoft Teams.
naftiko: "0.5"
info:
label: "New Employee Onboarding"
description: "When a new hire record is created in Workday, provisions a Microsoft 365 account, opens a ServiceNow IT onboarding ticket, and sends a welcome message via Microsoft Teams."
tags:
- hr
- onboarding
- workday
- microsoft-365
- servicenow
- msteams
capability:
exposes:
- type: mcp
namespace: hr-onboarding
port: 8080
tools:
- name: trigger-employee-onboarding
description: "Given a Workday employee ID and start date, provision a Microsoft 365 account, open a ServiceNow onboarding incident, and send a Teams welcome message. Use when HR confirms a new hire record."
inputParameters:
- name: workday_employee_id
in: body
type: string
description: "Workday worker ID for the new hire."
- name: start_date
in: body
type: string
description: "Employee start date in ISO 8601 format (YYYY-MM-DD)."
steps:
- name: get-worker
type: call
call: workday.get-worker
with:
worker_id: "{{workday_employee_id}}"
- name: provision-m365
type: call
call: msgraph.create-user
with:
displayName: "{{get-worker.full_name}}"
userPrincipalName: "{{get-worker.email}}"
department: "{{get-worker.department}}"
- name: open-ticket
type: call
call: servicenow.create-incident
with:
short_description: "IT Onboarding: {{get-worker.full_name}} starting {{start_date}}"
category: "onboarding"
assignment_group: "IT_Onboarding"
- name: send-welcome
type: call
call: msteams.post-welcome
with:
recipient_upn: "{{get-worker.email}}"
message: "Welcome to Elsevier, {{get-worker.first_name}}! Your IT ticket: {{open-ticket.number}}"
consumes:
- type: http
namespace: workday
baseUri: "https://wd2-impl-services1.workday.com/ccx/api/v1"
authentication:
type: bearer
token: "$secrets.workday_token"
resources:
- name: workers
path: "/workers/{{worker_id}}"
inputParameters:
- name: worker_id
in: path
operations:
- name: get-worker
method: GET
- type: http
namespace: msgraph
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msgraph_token"
resources:
- name: users
path: "/users"
operations:
- name: create-user
method: POST
- type: http
namespace: servicenow
baseUri: "https://elsevier.service-now.com/api/now"
authentication:
type: basic
username: "$secrets.servicenow_user"
password: "$secrets.servicenow_password"
resources:
- name: incidents
path: "/table/incident"
operations:
- name: create-incident
method: POST
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: messages
path: "/users/{{recipient_upn}}/sendMail"
inputParameters:
- name: recipient_upn
in: path
operations:
- name: post-welcome
method: POST
Assigns an Okta user to an application and logs the action to ServiceNow.
naftiko: "0.5"
info:
label: "Okta App Assignment"
description: "Assigns an Okta user to an application and logs the action to ServiceNow."
tags:
- identity
- provisioning
- okta
- servicenow
capability:
exposes:
- type: mcp
namespace: iam-ops
port: 8080
tools:
- name: assign-app
description: "Given an Okta user ID and app ID, assign the user and log to ServiceNow."
inputParameters:
- name: user_id
in: body
type: string
description: "Okta user ID."
- name: app_id
in: body
type: string
description: "Okta app ID."
steps:
- name: assign
type: call
call: okta.assign-app
with:
app_id: "{{app_id}}"
user_id: "{{user_id}}"
- name: log-audit
type: call
call: servicenow.create-record
with:
table: "u_access_audit"
user_id: "{{user_id}}"
app: "{{app_id}}"
action: "assigned"
consumes:
- type: http
namespace: okta
baseUri: "https://elsevier.okta.com/api/v1"
authentication:
type: bearer
token: "$secrets.okta_api_token"
resources:
- name: app-users
path: "/apps/{{app_id}}/users"
inputParameters:
- name: app_id
in: path
operations:
- name: assign-app
method: POST
- type: http
namespace: servicenow
baseUri: "https://elsevier.service-now.com/api/now"
authentication:
type: basic
username: "$secrets.servicenow_user"
password: "$secrets.servicenow_password"
resources:
- name: records
path: "/table/{{table}}"
inputParameters:
- name: table
in: path
operations:
- name: create-record
method: POST
Retrieves all Okta group memberships for a user for quarterly access certification.
naftiko: "0.5"
info:
label: "Okta User Access Review"
description: "Retrieves all Okta group memberships for a user for quarterly access certification."
tags:
- identity
- access-management
- okta
capability:
exposes:
- type: mcp
namespace: iam
port: 8080
tools:
- name: get-user-groups
description: "Given an Okta user ID, return all group memberships."
inputParameters:
- name: user_id
in: body
type: string
description: "Okta user ID."
call: okta.list-user-groups
with:
user_id: "{{user_id}}"
outputParameters:
- name: groups
type: array
mapping: "$.[*].profile.name"
consumes:
- type: http
namespace: okta
baseUri: "https://elsevier.okta.com/api/v1"
authentication:
type: bearer
token: "$secrets.okta_api_token"
resources:
- name: user-groups
path: "/users/{{user_id}}/groups"
inputParameters:
- name: user_id
in: path
operations:
- name: list-user-groups
method: GET
When an author accepts open-access publishing, creates an invoice in SAP, links it to the Salesforce opportunity, and notifies the author via email through Microsoft 365.
naftiko: "0.5"
info:
label: "Open Access Invoice Processing"
description: "When an author accepts open-access publishing, creates an invoice in SAP, links it to the Salesforce opportunity, and notifies the author via email through Microsoft 365."
tags:
- finance
- publishing
- open-access
- sap
- salesforce
- microsoft-365
capability:
exposes:
- type: mcp
namespace: oa-billing
port: 8080
tools:
- name: create-oa-invoice
description: "Given an article DOI, author institution ID, and APC amount, create a SAP billing document, link it to the Salesforce opportunity record, and send the invoice to the author via Microsoft 365 email."
inputParameters:
- name: article_doi
in: body
type: string
description: "Article DOI for the accepted open-access manuscript."
- name: institution_id
in: body
type: string
description: "Salesforce account ID for the author's institution."
- name: apc_amount
in: body
type: number
description: "Article Processing Charge in USD."
steps:
- name: get-opportunity
type: call
call: salesforce.get-opportunity-by-doi
with:
doi__c: "{{article_doi}}"
- name: create-invoice
type: call
call: sap.create-billing-document
with:
reference: "{{article_doi}}"
payer: "{{institution_id}}"
net_amount: "{{apc_amount}}"
- name: update-opportunity
type: call
call: salesforce-write.patch-opportunity
with:
opportunity_id: "{{get-opportunity.id}}"
SAP_Invoice_Number__c: "{{create-invoice.billing_doc_number}}"
StageName: "Invoice Sent"
consumes:
- type: http
namespace: salesforce
baseUri: "https://elsevier.my.salesforce.com/services/data/v58.0"
authentication:
type: bearer
token: "$secrets.salesforce_token"
resources:
- name: opportunities
path: "/query"
inputParameters:
- name: doi__c
in: query
operations:
- name: get-opportunity-by-doi
method: GET
- type: http
namespace: sap
baseUri: "https://elsevier-s4.sap.com/sap/opu/odata/sap/SD_BILLING_SRV"
authentication:
type: basic
username: "$secrets.sap_user"
password: "$secrets.sap_password"
resources:
- name: billing-documents
path: "/A_BillingDocument"
operations:
- name: create-billing-document
method: POST
- type: http
namespace: salesforce-write
baseUri: "https://elsevier.my.salesforce.com/services/data/v58.0"
authentication:
type: bearer
token: "$secrets.salesforce_token"
resources:
- name: opportunity-record
path: "/sobjects/Opportunity/{{opportunity_id}}"
inputParameters:
- name: opportunity_id
in: path
operations:
- name: patch-opportunity
method: PATCH
Uses OpenAI to generate a plain-language summary of an article abstract and stores it in Snowflake for discoverability.
naftiko: "0.5"
info:
label: "OpenAI Article Abstract Generation"
description: "Uses OpenAI to generate a plain-language summary of an article abstract and stores it in Snowflake for discoverability."
tags:
- ai
- publishing
- openai
- snowflake
capability:
exposes:
- type: mcp
namespace: content-ai
port: 8080
tools:
- name: generate-plain-summary
description: "Given an article DOI and abstract text, generate a plain-language summary via OpenAI and store in Snowflake."
inputParameters:
- name: doi
in: body
type: string
description: "Article DOI."
- name: abstract
in: body
type: string
description: "Original article abstract."
steps:
- name: generate-summary
type: call
call: openai.create-completion
with:
model: "gpt-4"
prompt: "Write a plain-language summary of this scientific abstract: {{abstract}}"
- name: store-summary
type: call
call: snowflake.insert-row
with:
table: "ARTICLE_SUMMARIES"
values:
doi: "{{doi}}"
plain_summary: "{{generate-summary.text}}"
consumes:
- type: http
namespace: openai
baseUri: "https://api.openai.com/v1"
authentication:
type: bearer
token: "$secrets.openai_api_key"
resources:
- name: completions
path: "/chat/completions"
operations:
- name: create-completion
method: POST
- type: http
namespace: snowflake
baseUri: "https://elsevier.snowflakecomputing.com/api/v2"
authentication:
type: bearer
token: "$secrets.snowflake_token"
resources:
- name: statements
path: "/statements"
operations:
- name: insert-row
method: POST
Uses OpenAI to analyze a manuscript abstract and suggest potential peer reviewers from the Scopus reviewer pool, then posts suggestions to Microsoft Teams.
naftiko: "0.5"
info:
label: "OpenAI Peer Review Matching"
description: "Uses OpenAI to analyze a manuscript abstract and suggest potential peer reviewers from the Scopus reviewer pool, then posts suggestions to Microsoft Teams."
tags:
- ai
- publishing
- openai
- microsoft-teams
capability:
exposes:
- type: mcp
namespace: editorial-ai
port: 8080
tools:
- name: suggest-reviewers
description: "Given an abstract, use OpenAI to extract key topics and suggest reviewer matches. Post suggestions to Teams."
inputParameters:
- name: manuscript_id
in: body
type: string
description: "Manuscript ID."
- name: abstract
in: body
type: string
description: "Manuscript abstract text."
steps:
- name: analyze-topics
type: call
call: openai.create-completion
with:
model: "gpt-4"
prompt: "Extract 5 key research topics from this abstract for peer reviewer matching: {{abstract}}"
- name: post-suggestions
type: call
call: msteams.post-channel-message
with:
channel_id: "editorial-ops"
text: "Reviewer suggestions for {{manuscript_id}}: {{analyze-topics.text}}"
consumes:
- type: http
namespace: openai
baseUri: "https://api.openai.com/v1"
authentication:
type: bearer
token: "$secrets.openai_api_key"
resources:
- name: completions
path: "/chat/completions"
operations:
- name: create-completion
method: POST
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/{{team_id}}/channels/{{channel_id}}/messages"
inputParameters:
- name: channel_id
in: path
operations:
- name: post-channel-message
method: POST
Retrieves a researcher profile from ORCID by ORCID ID, returning name, affiliations, and publication count.
naftiko: "0.5"
info:
label: "ORCID Researcher Profile Lookup"
description: "Retrieves a researcher profile from ORCID by ORCID ID, returning name, affiliations, and publication count."
tags:
- research
- publishing
- orcid
capability:
exposes:
- type: mcp
namespace: research-ops
port: 8080
tools:
- name: get-researcher-profile
description: "Given an ORCID ID, return the researcher's name, current affiliation, and works count."
inputParameters:
- name: orcid_id
in: body
type: string
description: "ORCID ID (e.g., 0000-0002-1234-5678)."
call: orcid.get-record
with:
orcid_id: "{{orcid_id}}"
outputParameters:
- name: name
type: string
mapping: "$.person.name.given-names.value"
- name: affiliation
type: string
mapping: "$.activities-summary.employments.affiliation-group[0].summaries[0].employment-summary.organization.name"
consumes:
- type: http
namespace: orcid
baseUri: "https://pub.orcid.org/v3.0"
authentication:
type: bearer
token: "$secrets.orcid_token"
resources:
- name: records
path: "/{{orcid_id}}/record"
inputParameters:
- name: orcid_id
in: path
operations:
- name: get-record
method: GET
Creates a Jira ticket from a PagerDuty incident and notifies the engineering Slack channel.
naftiko: "0.5"
info:
label: "PagerDuty Incident to Jira"
description: "Creates a Jira ticket from a PagerDuty incident and notifies the engineering Slack channel."
tags:
- incident-management
- engineering
- pagerduty
- jira
- slack
capability:
exposes:
- type: mcp
namespace: incident-ops
port: 8080
tools:
- name: create-jira-from-pd
description: "Given a PagerDuty incident ID, fetch details and create a Jira ticket."
inputParameters:
- name: incident_id
in: body
type: string
description: "PagerDuty incident ID."
steps:
- name: get-pd
type: call
call: pagerduty.get-incident
with:
incident_id: "{{incident_id}}"
- name: create-jira
type: call
call: jira.create-issue
with:
project_key: "OPS"
issuetype: "Bug"
summary: "PD: {{get-pd.incident.title}}"
- name: notify-eng
type: call
call: slack.post-message
with:
channel: "engineering"
text: "PD incident {{incident_id}} -> Jira {{create-jira.key}}"
consumes:
- type: http
namespace: pagerduty
baseUri: "https://api.pagerduty.com"
authentication:
type: bearer
token: "$secrets.pagerduty_token"
resources:
- name: incidents
path: "/incidents/{{incident_id}}"
inputParameters:
- name: incident_id
in: path
operations:
- name: get-incident
method: GET
- type: http
namespace: jira
baseUri: "https://elsevier.atlassian.net/rest/api/3"
authentication:
type: basic
username: "$secrets.jira_user"
password: "$secrets.jira_token"
resources:
- name: issues
path: "/issue"
operations:
- name: create-issue
method: POST
- type: http
namespace: slack
baseUri: "https://slack.com/api"
authentication:
type: bearer
token: "$secrets.slack_bot_token"
resources:
- name: messages
path: "/chat.postMessage"
operations:
- name: post-message
method: POST
Retrieves the current on-call engineer for a PagerDuty schedule.
naftiko: "0.5"
info:
label: "PagerDuty On-Call Lookup"
description: "Retrieves the current on-call engineer for a PagerDuty schedule."
tags:
- engineering
- incident-management
- pagerduty
capability:
exposes:
- type: mcp
namespace: incident-ops
port: 8080
tools:
- name: get-on-call
description: "Given a PagerDuty schedule ID, return the current on-call engineer's name and email."
inputParameters:
- name: schedule_id
in: body
type: string
description: "PagerDuty schedule ID."
call: pagerduty.get-on-call
with:
schedule_id: "{{schedule_id}}"
outputParameters:
- name: name
type: string
mapping: "$.schedule.final_schedule.rendered_schedule_entries[0].user.summary"
- name: email
type: string
mapping: "$.schedule.final_schedule.rendered_schedule_entries[0].user.email"
consumes:
- type: http
namespace: pagerduty
baseUri: "https://api.pagerduty.com"
authentication:
type: bearer
token: "$secrets.pagerduty_token"
resources:
- name: schedules
path: "/schedules/{{schedule_id}}"
inputParameters:
- name: schedule_id
in: path
operations:
- name: get-on-call
method: GET
Identifies qualified reviewers for a manuscript by querying Scopus author expertise, checks conflicts of interest in Salesforce, and creates reviewer tasks in ServiceNow.
naftiko: "0.5"
info:
label: "Peer Review Assignment"
description: "Identifies qualified reviewers for a manuscript by querying Scopus author expertise, checks conflicts of interest in Salesforce, and creates reviewer tasks in ServiceNow."
tags:
- publishing
- peer-review
- scopus
- salesforce
- servicenow
capability:
exposes:
- type: mcp
namespace: peer-review
port: 8080
tools:
- name: assign-reviewers
description: "Given a manuscript ID, subject keywords, and handling editor ID, query Scopus for top-cited authors in the field, screen them for conflicts in Salesforce, and open reviewer tasks in ServiceNow."
inputParameters:
- name: manuscript_id
in: body
type: string
description: "Manuscript identifier from the editorial system."
- name: subject_keywords
in: body
type: string
description: "Comma-separated subject keywords for expert matching (e.g., 'proteomics,mass spectrometry')."
- name: editor_id
in: body
type: string
description: "Workday employee ID of the handling editor."
steps:
- name: find-experts
type: call
call: scopus.search-authors-by-subject
with:
keywords: "{{subject_keywords}}"
limit: "5"
- name: create-review-task
type: call
call: servicenow.create-task
with:
short_description: "Peer review assignment: {{manuscript_id}}"
assignment_group: "Editorial_Operations"
description: "Manuscript {{manuscript_id}} requires reviewer assignment. Top candidates fetched from Scopus: {{find-experts.author_names}}"
consumes:
- type: http
namespace: scopus
baseUri: "https://api.elsevier.com/content/search/author"
authentication:
type: apikey
key: "X-ELS-APIKey"
value: "$secrets.scopus_api_key"
placement: header
resources:
- name: author-search
path: "/"
inputParameters:
- name: keywords
in: query
- name: limit
in: query
operations:
- name: search-authors-by-subject
method: GET
- type: http
namespace: servicenow
baseUri: "https://elsevier.service-now.com/api/now"
authentication:
type: basic
username: "$secrets.servicenow_user"
password: "$secrets.servicenow_password"
resources:
- name: tasks
path: "/table/task"
operations:
- name: create-task
method: POST
Retrieves the latest run results for a Postman API monitor.
naftiko: "0.5"
info:
label: "Postman API Health Monitor"
description: "Retrieves the latest run results for a Postman API monitor."
tags:
- engineering
- api-management
- postman
capability:
exposes:
- type: mcp
namespace: api-ops
port: 8080
tools:
- name: get-monitor-status
description: "Given a Postman monitor ID, return pass/fail counts."
inputParameters:
- name: monitor_id
in: body
type: string
description: "Postman monitor ID."
call: postman.get-monitor
with:
monitor_id: "{{monitor_id}}"
outputParameters:
- name: status
type: string
mapping: "$.monitor.lastRun.status"
- name: passed
type: integer
mapping: "$.monitor.lastRun.stats.assertions.passed"
consumes:
- type: http
namespace: postman
baseUri: "https://api.getpostman.com"
authentication:
type: apikey
key: "X-Api-Key"
value: "$secrets.postman_api_key"
placement: header
resources:
- name: monitors
path: "/monitors/{{monitor_id}}"
inputParameters:
- name: monitor_id
in: path
operations:
- name: get-monitor
method: GET
Triggers a scheduled Power BI dataset refresh for the editorial operations dashboard, verifying completion status and alerting via Teams on failure.
naftiko: "0.5"
info:
label: "Power BI Editorial Dashboard Refresh"
description: "Triggers a scheduled Power BI dataset refresh for the editorial operations dashboard, verifying completion status and alerting via Teams on failure."
tags:
- analytics
- reporting
- power-bi
- msteams
- monitoring
capability:
exposes:
- type: mcp
namespace: editorial-reporting
port: 8080
tools:
- name: refresh-editorial-dashboard
description: "Given a Power BI workspace ID and dataset ID, trigger a dataset refresh, poll for completion, and post a Teams notification with the refresh outcome. Use for daily editorial KPI dashboard updates."
inputParameters:
- name: workspace_id
in: body
type: string
description: "Power BI workspace (group) ID containing the editorial dataset."
- name: dataset_id
in: body
type: string
description: "Power BI dataset ID to refresh."
steps:
- name: trigger-refresh
type: call
call: powerbi.trigger-dataset-refresh
with:
workspace_id: "{{workspace_id}}"
dataset_id: "{{dataset_id}}"
- name: notify-completion
type: call
call: msteams.send-message
with:
channel: "editorial-ops"
text: "Power BI editorial dashboard refresh triggered for dataset {{dataset_id}} in workspace {{workspace_id}}."
consumes:
- type: http
namespace: powerbi
baseUri: "https://api.powerbi.com/v1.0/myorg"
authentication:
type: bearer
token: "$secrets.powerbi_token"
resources:
- name: dataset-refreshes
path: "/groups/{{workspace_id}}/datasets/{{dataset_id}}/refreshes"
inputParameters:
- name: workspace_id
in: path
- name: dataset_id
in: path
operations:
- name: trigger-dataset-refresh
method: POST
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/editorial/channels/general/messages"
operations:
- name: send-message
method: POST
Triggers a Power BI dataset refresh for platform usage analytics.
naftiko: "0.5"
info:
label: "Power BI Usage Dashboard Refresh"
description: "Triggers a Power BI dataset refresh for platform usage analytics."
tags:
- analytics
- reporting
- power-bi
capability:
exposes:
- type: mcp
namespace: bi-ops
port: 8080
tools:
- name: refresh-usage-dataset
description: "Given a Power BI dataset ID and workspace, trigger a refresh."
inputParameters:
- name: dataset_id
in: body
type: string
description: "Power BI dataset ID."
- name: group_id
in: body
type: string
description: "Power BI workspace group ID."
call: powerbi.refresh-dataset
with:
group_id: "{{group_id}}"
dataset_id: "{{dataset_id}}"
outputParameters:
- name: request_id
type: string
mapping: "$.requestId"
consumes:
- type: http
namespace: powerbi
baseUri: "https://api.powerbi.com/v1.0/myorg"
authentication:
type: bearer
token: "$secrets.powerbi_token"
resources:
- name: datasets
path: "/groups/{{group_id}}/datasets/{{dataset_id}}/refreshes"
inputParameters:
- name: group_id
in: path
- name: dataset_id
in: path
operations:
- name: refresh-dataset
method: POST
Enriches an author record in Salesforce with current affiliation and citation metrics fetched from Scopus, then updates the CRM contact.
naftiko: "0.5"
info:
label: "Researcher Profile Enrichment"
description: "Enriches an author record in Salesforce with current affiliation and citation metrics fetched from Scopus, then updates the CRM contact."
tags:
- publishing
- crm
- data-enrichment
- salesforce
- scopus
- reporting
capability:
exposes:
- type: mcp
namespace: researcher-data
port: 8080
tools:
- name: enrich-author-profile
description: "Given an author Scopus ID, fetch current institution affiliation and h-index from Scopus, then patch the Salesforce contact record with enriched data. Use during author onboarding or annual data refresh."
inputParameters:
- name: scopus_author_id
in: body
type: string
description: "Scopus numeric author identifier (e.g., 7402691548)."
- name: salesforce_contact_id
in: body
type: string
description: "Salesforce Contact record ID to update."
steps:
- name: fetch-scopus-profile
type: call
call: scopus.get-author
with:
author_id: "{{scopus_author_id}}"
- name: update-contact
type: call
call: salesforce-update.patch-contact
with:
contact_id: "{{salesforce_contact_id}}"
Current_Affiliation__c: "{{fetch-scopus-profile.affiliation}}"
H_Index__c: "{{fetch-scopus-profile.h_index}}"
Citation_Count__c: "{{fetch-scopus-profile.citation_count}}"
consumes:
- type: http
namespace: scopus
baseUri: "https://api.elsevier.com/content/author"
authentication:
type: apikey
key: "X-ELS-APIKey"
value: "$secrets.scopus_api_key"
placement: header
resources:
- name: author-profile
path: "/author_id/{{author_id}}"
inputParameters:
- name: author_id
in: path
operations:
- name: get-author
method: GET
- type: http
namespace: salesforce-update
baseUri: "https://elsevier.my.salesforce.com/services/data/v58.0"
authentication:
type: bearer
token: "$secrets.salesforce_token"
resources:
- name: contacts
path: "/sobjects/Contact/{{contact_id}}"
inputParameters:
- name: contact_id
in: path
operations:
- name: patch-contact
method: PATCH
Retrieves a Salesforce contact by email, returning name, title, account, and phone.
naftiko: "0.5"
info:
label: "Salesforce Contact Lookup"
description: "Retrieves a Salesforce contact by email, returning name, title, account, and phone."
tags:
- sales
- crm
- salesforce
capability:
exposes:
- type: mcp
namespace: crm-ops
port: 8080
tools:
- name: lookup-contact
description: "Given an email, look up the Salesforce contact record."
inputParameters:
- name: email
in: body
type: string
description: "Contact email."
call: salesforce.query-contact
with:
q: "SELECT Name, Title, Account.Name FROM Contact WHERE Email = '{{email}}'"
outputParameters:
- name: name
type: string
mapping: "$.records[0].Name"
- name: account
type: string
mapping: "$.records[0].Account.Name"
consumes:
- type: http
namespace: salesforce
baseUri: "https://elsevier.my.salesforce.com/services/data/v58.0"
authentication:
type: bearer
token: "$secrets.salesforce_token"
resources:
- name: query
path: "/query"
operations:
- name: query-contact
method: GET
Queries Salesforce for institutional subscriptions expiring within 60 days and posts the list to the sales Slack channel.
naftiko: "0.5"
info:
label: "Salesforce Institutional Renewal Alert"
description: "Queries Salesforce for institutional subscriptions expiring within 60 days and posts the list to the sales Slack channel."
tags:
- sales
- subscriptions
- salesforce
- slack
capability:
exposes:
- type: mcp
namespace: sales-ops
port: 8080
tools:
- name: alert-upcoming-renewals
description: "Fetch institutional subscriptions expiring within a threshold and notify the sales team via Slack."
inputParameters:
- name: days_threshold
in: body
type: integer
description: "Days until expiry threshold."
steps:
- name: query-renewals
type: call
call: salesforce.query
with:
q: "SELECT Account.Name, EndDate, Amount FROM Contract WHERE EndDate = NEXT_N_DAYS:{{days_threshold}} AND Status = 'Active'"
- name: post-alert
type: call
call: slack.post-message
with:
channel: "sales-renewals"
text: "Upcoming renewals (next {{days_threshold}} days): {{query-renewals.totalSize}} contracts expiring"
consumes:
- type: http
namespace: salesforce
baseUri: "https://elsevier.my.salesforce.com/services/data/v58.0"
authentication:
type: bearer
token: "$secrets.salesforce_token"
resources:
- name: query
path: "/query"
operations:
- name: query
method: GET
- type: http
namespace: slack
baseUri: "https://slack.com/api"
authentication:
type: bearer
token: "$secrets.slack_bot_token"
resources:
- name: messages
path: "/chat.postMessage"
operations:
- name: post-message
method: POST
Pulls open opportunity pipeline from Salesforce, writes the forecast data to Snowflake, and triggers a Power BI quarterly revenue forecast refresh.
naftiko: "0.5"
info:
label: "Salesforce Opportunity Forecast Sync"
description: "Pulls open opportunity pipeline from Salesforce, writes the forecast data to Snowflake, and triggers a Power BI quarterly revenue forecast refresh."
tags:
- sales
- finance
- crm
- salesforce
- snowflake
- power-bi
- forecasting
capability:
exposes:
- type: mcp
namespace: sales-forecasting
port: 8080
tools:
- name: sync-opportunity-forecast
description: "Given a Salesforce fiscal quarter label, export open and committed opportunities, write them to Snowflake, and trigger a Power BI forecast refresh. Use before quarterly business review preparation."
inputParameters:
- name: fiscal_quarter
in: body
type: string
description: "Salesforce fiscal quarter label (e.g., Q2-2026)."
steps:
- name: export-opportunities
type: call
call: salesforce.query-open-opportunities
with:
fiscal_quarter: "{{fiscal_quarter}}"
- name: write-forecast
type: call
call: snowflake.insert-forecast-rows
with:
fiscal_quarter: "{{fiscal_quarter}}"
records: "{{export-opportunities.records}}"
- name: refresh-powerbi
type: call
call: powerbi.trigger-refresh
with:
dataset_id: "$secrets.powerbi_forecast_dataset_id"
consumes:
- type: http
namespace: salesforce
baseUri: "https://elsevier.my.salesforce.com/services/data/v58.0"
authentication:
type: bearer
token: "$secrets.salesforce_token"
resources:
- name: opportunities
path: "/query"
inputParameters:
- name: fiscal_quarter
in: query
operations:
- name: query-open-opportunities
method: GET
- type: http
namespace: snowflake
baseUri: "https://elsevier.snowflakecomputing.com/api/v2"
authentication:
type: bearer
token: "$secrets.snowflake_token"
resources:
- name: forecast-table
path: "/statements"
operations:
- name: insert-forecast-rows
method: POST
- type: http
namespace: powerbi
baseUri: "https://api.powerbi.com/v1.0/myorg"
authentication:
type: bearer
token: "$secrets.powerbi_token"
resources:
- name: dataset-refreshes
path: "/datasets/{{dataset_id}}/refreshes"
inputParameters:
- name: dataset_id
in: path
operations:
- name: trigger-refresh
method: POST
Retrieves a SAP Ariba contract by ID, returning status, vendor, value, and expiry date.
naftiko: "0.5"
info:
label: "SAP Ariba Contract Status Lookup"
description: "Retrieves a SAP Ariba contract by ID, returning status, vendor, value, and expiry date."
tags:
- procurement
- contracts
- sap-ariba
capability:
exposes:
- type: mcp
namespace: procurement-ops
port: 8080
tools:
- name: get-contract-status
description: "Given a SAP Ariba contract ID, return status, vendor name, total value, and expiry date."
inputParameters:
- name: contract_id
in: body
type: string
description: "SAP Ariba contract ID."
call: ariba.get-contract
with:
contract_id: "{{contract_id}}"
outputParameters:
- name: status
type: string
mapping: "$.status"
- name: vendor
type: string
mapping: "$.supplier.name"
- name: expiry_date
type: string
mapping: "$.expirationDate"
consumes:
- type: http
namespace: ariba
baseUri: "https://openapi.ariba.com/api/contract-compliance/v1"
authentication:
type: bearer
token: "$secrets.ariba_token"
resources:
- name: contracts
path: "/contracts/{{contract_id}}"
inputParameters:
- name: contract_id
in: path
operations:
- name: get-contract
method: GET
When a purchase requisition exceeds the approval threshold in SAP Ariba, looks up the approver in Workday, creates an approval task in ServiceNow, and notifies the approver via Teams.
naftiko: "0.5"
info:
label: "SAP Ariba Purchase Order Approval"
description: "When a purchase requisition exceeds the approval threshold in SAP Ariba, looks up the approver in Workday, creates an approval task in ServiceNow, and notifies the approver via Teams."
tags:
- procurement
- finance
- sap-ariba
- workday
- servicenow
- approval
capability:
exposes:
- type: mcp
namespace: procurement-approval
port: 8080
tools:
- name: trigger-po-approval
description: "Given an SAP Ariba requisition ID and amount, look up the cost center approver in Workday, open a ServiceNow approval task, and send a Teams notification to the approver. Use for POs above the $50k auto-approve threshold."
inputParameters:
- name: requisition_id
in: body
type: string
description: "SAP Ariba purchase requisition ID."
- name: amount
in: body
type: number
description: "Requisition total amount in USD."
- name: cost_center
in: body
type: string
description: "SAP cost center code for the purchase."
steps:
- name: get-approver
type: call
call: workday.get-cost-center-manager
with:
cost_center: "{{cost_center}}"
- name: create-approval-task
type: call
call: servicenow.create-task
with:
short_description: "PO Approval Required: {{requisition_id}} — ${{amount}}"
assignment: "{{get-approver.email}}"
description: "Ariba requisition {{requisition_id}} requires approval. Amount: ${{amount}}. Cost center: {{cost_center}}"
- name: notify-approver
type: call
call: msteams.send-message
with:
recipient_upn: "{{get-approver.email}}"
text: "Action required: PO approval for requisition {{requisition_id}} (${{amount}}). Task: {{create-approval-task.number}}"
consumes:
- type: http
namespace: workday
baseUri: "https://wd2-impl-services1.workday.com/ccx/api/v1"
authentication:
type: bearer
token: "$secrets.workday_token"
resources:
- name: cost-center-managers
path: "/costCenters/{{cost_center}}/manager"
inputParameters:
- name: cost_center
in: path
operations:
- name: get-cost-center-manager
method: GET
- type: http
namespace: servicenow
baseUri: "https://elsevier.service-now.com/api/now"
authentication:
type: basic
username: "$secrets.servicenow_user"
password: "$secrets.servicenow_password"
resources:
- name: tasks
path: "/table/task"
operations:
- name: create-task
method: POST
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: messages
path: "/users/{{recipient_upn}}/sendMail"
inputParameters:
- name: recipient_upn
in: path
operations:
- name: send-message
method: POST
Queries SAP Concur for unsubmitted expense reports and sends reminders via Microsoft Graph.
naftiko: "0.5"
info:
label: "SAP Concur Expense Reminder"
description: "Queries SAP Concur for unsubmitted expense reports and sends reminders via Microsoft Graph."
tags:
- finance
- expense-management
- sap-concur
- microsoft-teams
capability:
exposes:
- type: mcp
namespace: finance-ops
port: 8080
tools:
- name: send-expense-reminders
description: "Fetch unsubmitted Concur reports and send email reminders."
inputParameters:
- name: days_threshold
in: body
type: integer
description: "Days since creation threshold."
steps:
- name: get-unsubmitted
type: call
call: concur.list-reports
with:
status: "UNSUBMITTED"
older_than_days: "{{days_threshold}}"
- name: send-reminders
type: call
call: msgraph.send-mail
with:
recipients: "{{get-unsubmitted.owner_emails}}"
subject: "Please submit your expense report"
body: "You have an unsubmitted expense report older than {{days_threshold}} days."
consumes:
- type: http
namespace: concur
baseUri: "https://us.api.concursolutions.com/api/v3.0"
authentication:
type: bearer
token: "$secrets.concur_token"
resources:
- name: reports
path: "/expense/reports"
operations:
- name: list-reports
method: GET
- type: http
namespace: msgraph
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msgraph_token"
resources:
- name: mail
path: "/me/sendMail"
operations:
- name: send-mail
method: POST
Retrieves purchase order, goods receipt, and invoice data from SAP to perform a three-way match verification.
naftiko: "0.5"
info:
label: "SAP Invoice Three-Way Match"
description: "Retrieves purchase order, goods receipt, and invoice data from SAP to perform a three-way match verification."
tags:
- finance
- procurement
- sap
capability:
exposes:
- type: mcp
namespace: finance-ops
port: 8080
tools:
- name: verify-three-way-match
description: "Given a SAP invoice number, verify the PO amount, goods receipt quantity, and invoice total match."
inputParameters:
- name: invoice_number
in: body
type: string
description: "SAP invoice document number."
steps:
- name: get-invoice
type: call
call: sap.get-invoice
with:
invoice_number: "{{invoice_number}}"
- name: get-po
type: call
call: sap.get-po
with:
po_number: "{{get-invoice.po_number}}"
- name: get-gr
type: call
call: sap.get-goods-receipt
with:
doc_number: "{{get-invoice.gr_document}}"
consumes:
- type: http
namespace: sap
baseUri: "https://elsevier-s4.sap.com/sap/opu/odata/sap"
authentication:
type: basic
username: "$secrets.sap_user"
password: "$secrets.sap_password"
resources:
- name: invoices
path: "/API_SUPPLIERINVOICE_PROCESS_SRV/A_SupplierInvoice('{{invoice_number}}')"
inputParameters:
- name: invoice_number
in: path
operations:
- name: get-invoice
method: GET
- name: purchase-orders
path: "/MM_PUR_PO_MAINT_V2_SRV/A_PurchaseOrder('{{po_number}}')"
inputParameters:
- name: po_number
in: path
operations:
- name: get-po
method: GET
- name: goods-receipts
path: "/API_MATERIAL_DOCUMENT_SRV/A_MaterialDocumentHeader('{{doc_number}}')"
inputParameters:
- name: doc_number
in: path
operations:
- name: get-goods-receipt
method: GET
At month end, queries SAP for open accounting documents, creates a ServiceNow change request for the close checklist, and notifies the finance team via Teams.
naftiko: "0.5"
info:
label: "SAP Period Close Checklist"
description: "At month end, queries SAP for open accounting documents, creates a ServiceNow change request for the close checklist, and notifies the finance team via Teams."
tags:
- finance
- erp
- sap
- servicenow
- msteams
- period-close
capability:
exposes:
- type: mcp
namespace: finance-close
port: 8080
tools:
- name: run-period-close-checklist
description: "Given a fiscal period and company code, query SAP for open items, open a ServiceNow change request for period close, and notify the finance team in Teams. Use at the start of month-end close procedures."
inputParameters:
- name: fiscal_period
in: body
type: string
description: "SAP fiscal period in YYYYMM format (e.g., 202503)."
- name: company_code
in: body
type: string
description: "SAP company code (e.g., ELS1)."
steps:
- name: get-open-items
type: call
call: sap.get-open-items
with:
fiscal_period: "{{fiscal_period}}"
company_code: "{{company_code}}"
- name: create-change-request
type: call
call: servicenow.create-change-request
with:
short_description: "Period Close {{fiscal_period}} — {{company_code}}"
category: "financial_close"
description: "Open items count: {{get-open-items.open_count}}. SAP company code: {{company_code}}"
- name: notify-finance
type: call
call: msteams.send-message
with:
channel: "finance-close"
text: "Period close initiated for {{fiscal_period}} / {{company_code}}. Open items: {{get-open-items.open_count}}. Change: {{create-change-request.number}}"
consumes:
- type: http
namespace: sap
baseUri: "https://elsevier-s4.sap.com/sap/opu/odata/sap/FI_PERIOD_CLOSE_SRV"
authentication:
type: basic
username: "$secrets.sap_user"
password: "$secrets.sap_password"
resources:
- name: open-items
path: "/A_OpenItem"
inputParameters:
- name: fiscal_period
in: query
- name: company_code
in: query
operations:
- name: get-open-items
method: GET
- type: http
namespace: servicenow
baseUri: "https://elsevier.service-now.com/api/now"
authentication:
type: basic
username: "$secrets.servicenow_user"
password: "$secrets.servicenow_password"
resources:
- name: change-requests
path: "/table/change_request"
operations:
- name: create-change-request
method: POST
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/finance/channels/general/messages"
operations:
- name: send-message
method: POST
Retrieves vendor payment status from SAP by vendor number and invoice.
naftiko: "0.5"
info:
label: "SAP Vendor Payment Status"
description: "Retrieves vendor payment status from SAP by vendor number and invoice."
tags:
- finance
- erp
- sap
capability:
exposes:
- type: mcp
namespace: finance-ops
port: 8080
tools:
- name: get-payment-status
description: "Given a SAP vendor number and invoice, return payment status and scheduled date."
inputParameters:
- name: vendor_number
in: body
type: string
description: "SAP vendor number."
- name: invoice_number
in: body
type: string
description: "Invoice number."
call: sap.get-payment
with:
vendor: "{{vendor_number}}"
invoice: "{{invoice_number}}"
outputParameters:
- name: status
type: string
mapping: "$.d.PaymentStatus"
- name: scheduled_date
type: string
mapping: "$.d.PlannedPaymentDate"
consumes:
- type: http
namespace: sap
baseUri: "https://elsevier-s4.sap.com/sap/opu/odata/sap/API_SUPPLIERINVOICE_PROCESS_SRV"
authentication:
type: basic
username: "$secrets.sap_user"
password: "$secrets.sap_password"
resources:
- name: payments
path: "/A_SupplierInvoice"
operations:
- name: get-payment
method: GET
Retrieves article download statistics from Snowflake for a given DOI and journal.
naftiko: "0.5"
info:
label: "ScienceDirect Article Download Stats"
description: "Retrieves article download statistics from Snowflake for a given DOI and journal."
tags:
- publishing
- analytics
- snowflake
capability:
exposes:
- type: mcp
namespace: content-analytics
port: 8080
tools:
- name: get-download-stats
description: "Given a DOI, return total downloads, monthly trend, and top institutions from Snowflake."
inputParameters:
- name: doi
in: body
type: string
description: "Article DOI."
call: snowflake.execute-statement
with:
statement: "SELECT total_downloads, monthly_downloads, top_institutions FROM article_stats WHERE doi = '{{doi}}'"
outputParameters:
- name: data
type: array
mapping: "$.data"
consumes:
- type: http
namespace: snowflake
baseUri: "https://elsevier.snowflakecomputing.com/api/v2"
authentication:
type: bearer
token: "$secrets.snowflake_token"
resources:
- name: statements
path: "/statements"
operations:
- name: execute-statement
method: POST
Periodically checks Scopus for newly retracted articles associated with Elsevier journals, logs them in Snowflake, and notifies the editorial team via Teams.
naftiko: "0.5"
info:
label: "Scopus Article Retraction Monitor"
description: "Periodically checks Scopus for newly retracted articles associated with Elsevier journals, logs them in Snowflake, and notifies the editorial team via Teams."
tags:
- publishing
- compliance
- scopus
- snowflake
- msteams
- monitoring
capability:
exposes:
- type: mcp
namespace: retraction-monitor
port: 8080
tools:
- name: check-retractions
description: "Given a journal ISSN and a lookback window in days, query Scopus for retracted articles, write each retraction to Snowflake for audit, and post a summary to the editorial Teams channel."
inputParameters:
- name: journal_issn
in: body
type: string
description: "Journal ISSN to check for recent retractions."
- name: lookback_days
in: body
type: integer
description: "Number of days to look back for newly indexed retractions."
steps:
- name: search-retractions
type: call
call: scopus.search-retractions
with:
issn: "{{journal_issn}}"
days: "{{lookback_days}}"
- name: write-audit-log
type: call
call: snowflake.insert-retraction-log
with:
issn: "{{journal_issn}}"
retraction_dois: "{{search-retractions.dois}}"
count: "{{search-retractions.count}}"
- name: notify-editorial
type: call
call: msteams.send-message
with:
channel: "editorial-alerts"
text: "Retraction check for ISSN {{journal_issn}}: {{search-retractions.count}} retractions found in last {{lookback_days}} days."
consumes:
- type: http
namespace: scopus
baseUri: "https://api.elsevier.com/content/search/scopus"
authentication:
type: apikey
key: "X-ELS-APIKey"
value: "$secrets.scopus_api_key"
placement: header
resources:
- name: article-search
path: "/"
inputParameters:
- name: issn
in: query
- name: days
in: query
operations:
- name: search-retractions
method: GET
- type: http
namespace: snowflake
baseUri: "https://elsevier.snowflakecomputing.com/api/v2"
authentication:
type: bearer
token: "$secrets.snowflake_token"
resources:
- name: retraction-log
path: "/statements"
operations:
- name: insert-retraction-log
method: POST
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/editorial/channels/alerts/messages"
operations:
- name: send-message
method: POST
Searches Scopus for an author by name and returns matching author profiles with publication counts.
naftiko: "0.5"
info:
label: "Scopus Author Search"
description: "Searches Scopus for an author by name and returns matching author profiles with publication counts."
tags:
- research
- publishing
- scopus
capability:
exposes:
- type: mcp
namespace: research-ops
port: 8080
tools:
- name: search-author
description: "Given an author name, search Scopus and return matching profiles with h-index and document count."
inputParameters:
- name: author_name
in: body
type: string
description: "Author name to search."
call: scopus.search-author
with:
query: "AUTHNAME({{author_name}})"
outputParameters:
- name: authors
type: array
mapping: "$.search-results.entry"
consumes:
- type: http
namespace: scopus
baseUri: "https://api.elsevier.com/content"
authentication:
type: apikey
key: "X-ELS-APIKey"
value: "$secrets.scopus_api_key"
placement: header
resources:
- name: author-search
path: "/search/author"
operations:
- name: search-author
method: GET
Retrieves the citation count for an article in Scopus by DOI, returning total citations and h-index context.
naftiko: "0.5"
info:
label: "Scopus Citation Count Lookup"
description: "Retrieves the citation count for an article in Scopus by DOI, returning total citations and h-index context."
tags:
- publishing
- research
- scopus
capability:
exposes:
- type: mcp
namespace: research-ops
port: 8080
tools:
- name: get-citation-count
description: "Given an article DOI, return the total citation count from Scopus."
inputParameters:
- name: doi
in: body
type: string
description: "Article DOI."
call: scopus.get-citations
with:
doi: "{{doi}}"
outputParameters:
- name: citation_count
type: integer
mapping: "$.search-results.entry[0].citedby-count"
- name: title
type: string
mapping: "$.search-results.entry[0].dc:title"
consumes:
- type: http
namespace: scopus
baseUri: "https://api.elsevier.com/content"
authentication:
type: apikey
key: "X-ELS-APIKey"
value: "$secrets.scopus_api_key"
placement: header
resources:
- name: search
path: "/search/scopus"
operations:
- name: get-citations
method: GET
Sends a transactional email to an author via SendGrid for manuscript status notifications.
naftiko: "0.5"
info:
label: "SendGrid Author Email Delivery"
description: "Sends a transactional email to an author via SendGrid for manuscript status notifications."
tags:
- communications
- publishing
- sendgrid
capability:
exposes:
- type: mcp
namespace: comms-ops
port: 8080
tools:
- name: send-author-email
description: "Given an author email, subject, and body, send a transactional email via SendGrid."
inputParameters:
- name: to_email
in: body
type: string
description: "Author email address."
- name: subject
in: body
type: string
description: "Email subject."
- name: body
in: body
type: string
description: "Email body."
call: sendgrid.send-email
with:
to: "{{to_email}}"
subject: "{{subject}}"
content: "{{body}}"
outputParameters:
- name: status_code
type: integer
mapping: "$.statusCode"
consumes:
- type: http
namespace: sendgrid
baseUri: "https://api.sendgrid.com/v3"
authentication:
type: bearer
token: "$secrets.sendgrid_api_key"
resources:
- name: mail
path: "/mail/send"
operations:
- name: send-email
method: POST
Looks up a ServiceNow change request, validates it against the CAB schedule, and notifies the change owner via Teams with approval status.
naftiko: "0.5"
info:
label: "ServiceNow Change Request Approval"
description: "Looks up a ServiceNow change request, validates it against the CAB schedule, and notifies the change owner via Teams with approval status."
tags:
- itsm
- change-management
- servicenow
- msteams
- approval
capability:
exposes:
- type: mcp
namespace: change-management
port: 8080
tools:
- name: get-change-request-status
description: "Given a ServiceNow change request number, fetch its current state, approval status, and scheduled window, then send a Teams summary to the change owner. Use for CAB preparation and stakeholder updates."
inputParameters:
- name: change_number
in: body
type: string
description: "ServiceNow change request number (e.g., CHG0012345)."
steps:
- name: get-change
type: call
call: servicenow.get-change-request
with:
number: "{{change_number}}"
- name: notify-owner
type: call
call: msteams.send-message
with:
channel: "change-management"
text: "Change {{change_number}} status: {{get-change.state}} | Approval: {{get-change.approval}} | Window: {{get-change.start_date}} to {{get-change.end_date}}"
consumes:
- type: http
namespace: servicenow
baseUri: "https://elsevier.service-now.com/api/now"
authentication:
type: basic
username: "$secrets.servicenow_user"
password: "$secrets.servicenow_password"
resources:
- name: change-requests
path: "/table/change_request"
inputParameters:
- name: number
in: query
operations:
- name: get-change-request
method: GET
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/it/channels/change-management/messages"
operations:
- name: send-message
method: POST
When a P1 ServiceNow incident is created, creates a corresponding Jira engineering ticket and notifies Microsoft Teams.
naftiko: "0.5"
info:
label: "ServiceNow Incident to Jira"
description: "When a P1 ServiceNow incident is created, creates a corresponding Jira engineering ticket and notifies Microsoft Teams."
tags:
- it-operations
- incident-management
- servicenow
- jira
- microsoft-teams
capability:
exposes:
- type: mcp
namespace: incident-ops
port: 8080
tools:
- name: escalate-to-engineering
description: "Given a ServiceNow incident number, create a Jira ticket and notify Teams."
inputParameters:
- name: incident_number
in: body
type: string
description: "ServiceNow incident number."
steps:
- name: get-incident
type: call
call: servicenow.get-incident
with:
number: "{{incident_number}}"
- name: create-jira
type: call
call: jira.create-issue
with:
project_key: "ENG"
issuetype: "Bug"
summary: "SNOW {{incident_number}}: {{get-incident.short_description}}"
- name: notify-teams
type: call
call: msteams.post-channel-message
with:
channel_id: "engineering-incidents"
text: "P1 escalated: {{incident_number}} | Jira: {{create-jira.key}}"
consumes:
- type: http
namespace: servicenow
baseUri: "https://elsevier.service-now.com/api/now"
authentication:
type: basic
username: "$secrets.servicenow_user"
password: "$secrets.servicenow_password"
resources:
- name: incidents
path: "/table/incident"
operations:
- name: get-incident
method: GET
- type: http
namespace: jira
baseUri: "https://elsevier.atlassian.net/rest/api/3"
authentication:
type: basic
username: "$secrets.jira_user"
password: "$secrets.jira_token"
resources:
- name: issues
path: "/issue"
operations:
- name: create-issue
method: POST
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/{{team_id}}/channels/{{channel_id}}/messages"
inputParameters:
- name: channel_id
in: path
operations:
- name: post-channel-message
method: POST
Retrieves the status of a ServiceNow IT service request by request number.
naftiko: "0.5"
info:
label: "ServiceNow IT Request Status"
description: "Retrieves the status of a ServiceNow IT service request by request number."
tags:
- it-operations
- support
- servicenow
capability:
exposes:
- type: mcp
namespace: it-ops
port: 8080
tools:
- name: get-request-status
description: "Given a ServiceNow request number, return the current state, assigned group, and expected resolution date."
inputParameters:
- name: request_number
in: body
type: string
description: "ServiceNow request number."
call: servicenow.get-request
with:
number: "{{request_number}}"
outputParameters:
- name: state
type: string
mapping: "$.result.state"
- name: assigned_group
type: string
mapping: "$.result.assignment_group.display_value"
consumes:
- type: http
namespace: servicenow
baseUri: "https://elsevier.service-now.com/api/now"
authentication:
type: basic
username: "$secrets.servicenow_user"
password: "$secrets.servicenow_password"
resources:
- name: requests
path: "/table/sc_request"
operations:
- name: get-request
method: GET
Searches a SharePoint document library by keyword and returns matching files.
naftiko: "0.5"
info:
label: "SharePoint Document Library Search"
description: "Searches a SharePoint document library by keyword and returns matching files."
tags:
- collaboration
- document-management
- sharepoint
capability:
exposes:
- type: mcp
namespace: doc-ops
port: 8080
tools:
- name: search-documents
description: "Given a SharePoint site ID and search keyword, return matching documents."
inputParameters:
- name: site_id
in: body
type: string
description: "SharePoint site ID."
- name: keyword
in: body
type: string
description: "Search keyword."
call: sharepoint.search
with:
site_id: "{{site_id}}"
query: "{{keyword}}"
outputParameters:
- name: files
type: array
mapping: "$.value"
consumes:
- type: http
namespace: sharepoint
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msgraph_token"
resources:
- name: search
path: "/sites/{{site_id}}/drive/root/search(q='{{query}}')"
inputParameters:
- name: site_id
in: path
- name: query
in: path
operations:
- name: search
method: GET
Posts a daily standup prompt to the editorial Slack channel and collects responses for the team lead.
naftiko: "0.5"
info:
label: "Slack Editorial Standup Bot"
description: "Posts a daily standup prompt to the editorial Slack channel and collects responses for the team lead."
tags:
- publishing
- collaboration
- slack
capability:
exposes:
- type: mcp
namespace: editorial-ops
port: 8080
tools:
- name: post-standup-prompt
description: "Post a daily standup prompt to the editorial Slack channel with manuscript pipeline summary."
inputParameters:
- name: slack_channel
in: body
type: string
description: "Slack channel for standup."
- name: pipeline_summary
in: body
type: string
description: "Current manuscript pipeline summary text."
call: slack.post-message
with:
channel: "{{slack_channel}}"
text: "Daily Editorial Standup\nPipeline: {{pipeline_summary}}\nPlease share your updates."
outputParameters:
- name: message_ts
type: string
mapping: "$.ts"
consumes:
- type: http
namespace: slack
baseUri: "https://slack.com/api"
authentication:
type: bearer
token: "$secrets.slack_bot_token"
resources:
- name: messages
path: "/chat.postMessage"
operations:
- name: post-message
method: POST
Queries Snowflake for weekly publishing metrics and posts a digest to the leadership Slack channel.
naftiko: "0.5"
info:
label: "Slack Weekly Publishing Digest"
description: "Queries Snowflake for weekly publishing metrics and posts a digest to the leadership Slack channel."
tags:
- publishing
- analytics
- snowflake
- slack
capability:
exposes:
- type: mcp
namespace: publishing-ops
port: 8080
tools:
- name: post-publishing-digest
description: "Fetch weekly publishing metrics from Snowflake and post to the leadership Slack channel."
inputParameters:
- name: slack_channel
in: body
type: string
description: "Slack channel."
steps:
- name: fetch-metrics
type: call
call: snowflake.execute-statement
with:
statement: "SELECT articles_published, reviews_completed, avg_review_time FROM weekly_metrics WHERE week_ending = CURRENT_DATE"
- name: post-digest
type: call
call: slack.post-message
with:
channel: "{{slack_channel}}"
text: "Weekly publishing digest: {{fetch-metrics.data}}"
consumes:
- type: http
namespace: snowflake
baseUri: "https://elsevier.snowflakecomputing.com/api/v2"
authentication:
type: bearer
token: "$secrets.snowflake_token"
resources:
- name: statements
path: "/statements"
operations:
- name: execute-statement
method: POST
- type: http
namespace: slack
baseUri: "https://slack.com/api"
authentication:
type: bearer
token: "$secrets.slack_bot_token"
resources:
- name: messages
path: "/chat.postMessage"
operations:
- name: post-message
method: POST
Checks Snowflake query history for failed or long-running jobs, logs anomalies to Datadog, and opens a Jira task for the data engineering team.
naftiko: "0.5"
info:
label: "Snowflake Data Pipeline Monitor"
description: "Checks Snowflake query history for failed or long-running jobs, logs anomalies to Datadog, and opens a Jira task for the data engineering team."
tags:
- data-engineering
- analytics
- snowflake
- datadog
- jira
- monitoring
capability:
exposes:
- type: mcp
namespace: data-ops
port: 8080
tools:
- name: monitor-snowflake-pipelines
description: "Given a Snowflake warehouse name and a failure threshold in minutes, query job history for failed or stalled jobs, send a metric to Datadog, and open a Jira task if failures are found. Use for daily pipeline health checks."
inputParameters:
- name: warehouse_name
in: body
type: string
description: "Snowflake virtual warehouse name to inspect (e.g., ANALYTICS_WH)."
- name: failure_threshold_minutes
in: body
type: integer
description: "Minimum run time in minutes to flag a query as stalled."
steps:
- name: query-job-history
type: call
call: snowflake.get-query-history
with:
warehouse: "{{warehouse_name}}"
threshold_minutes: "{{failure_threshold_minutes}}"
- name: post-metric
type: call
call: datadog.submit-metric
with:
metric: "elsevier.snowflake.failed_jobs"
points: "{{query-job-history.failure_count}}"
tags: "warehouse:{{warehouse_name}}"
- name: open-jira-task
type: call
call: jira.create-issue
with:
project_key: "DATA"
issuetype: "Task"
summary: "Snowflake pipeline failures in {{warehouse_name}}: {{query-job-history.failure_count}} jobs"
description: "Failed jobs detected: {{query-job-history.failed_job_names}}. Threshold: {{failure_threshold_minutes}} min."
consumes:
- type: http
namespace: snowflake
baseUri: "https://elsevier.snowflakecomputing.com/api/v2"
authentication:
type: bearer
token: "$secrets.snowflake_token"
resources:
- name: query-history
path: "/statements"
inputParameters:
- name: warehouse
in: query
- name: threshold_minutes
in: query
operations:
- name: get-query-history
method: POST
- type: http
namespace: datadog
baseUri: "https://api.datadoghq.com/api/v1"
authentication:
type: apikey
key: "DD-API-KEY"
value: "$secrets.datadog_api_key"
placement: header
resources:
- name: metrics
path: "/series"
operations:
- name: submit-metric
method: POST
- type: http
namespace: jira
baseUri: "https://elsevier.atlassian.net/rest/api/3"
authentication:
type: basic
username: "$secrets.jira_user"
password: "$secrets.jira_api_token"
resources:
- name: issues
path: "/issue"
operations:
- name: create-issue
method: POST
Executes a read-only SQL query against the Snowflake content usage analytics warehouse.
naftiko: "0.5"
info:
label: "Snowflake Usage Analytics Query"
description: "Executes a read-only SQL query against the Snowflake content usage analytics warehouse."
tags:
- data
- analytics
- snowflake
capability:
exposes:
- type: mcp
namespace: data-ops
port: 8080
tools:
- name: run-usage-query
description: "Given a SQL query, execute it against the Snowflake usage analytics warehouse and return results."
inputParameters:
- name: sql
in: body
type: string
description: "Read-only SQL query."
call: snowflake.execute-statement
with:
statement: "{{sql}}"
warehouse: "USAGE_ANALYTICS_WH"
outputParameters:
- name: rows
type: array
mapping: "$.data"
- name: row_count
type: integer
mapping: "$.resultSetMetaData.numRows"
consumes:
- type: http
namespace: snowflake
baseUri: "https://elsevier.snowflakecomputing.com/api/v2"
authentication:
type: bearer
token: "$secrets.snowflake_token"
resources:
- name: statements
path: "/statements"
operations:
- name: execute-statement
method: POST
Runs a Splunk saved search for security events and creates a ServiceNow incident if critical findings exist.
naftiko: "0.5"
info:
label: "Splunk Security Log Search"
description: "Runs a Splunk saved search for security events and creates a ServiceNow incident if critical findings exist."
tags:
- security
- siem
- splunk
- servicenow
capability:
exposes:
- type: mcp
namespace: security-ops
port: 8080
tools:
- name: search-security-logs
description: "Run a Splunk saved search and create ServiceNow incidents for critical findings."
inputParameters:
- name: search_name
in: body
type: string
description: "Splunk saved search name."
steps:
- name: run-search
type: call
call: splunk.dispatch-search
with:
name: "{{search_name}}"
- name: create-incident
type: call
call: servicenow.create-incident
with:
short_description: "Splunk finding: {{search_name}}"
category: "Security"
impact: "1"
consumes:
- type: http
namespace: splunk
baseUri: "https://elsevier-splunk.splunkcloud.com:8089/servicesNS/admin/search"
authentication:
type: bearer
token: "$secrets.splunk_token"
resources:
- name: saved-searches
path: "/saved/searches/{{name}}/dispatch"
inputParameters:
- name: name
in: path
operations:
- name: dispatch-search
method: POST
- type: http
namespace: servicenow
baseUri: "https://elsevier.service-now.com/api/now"
authentication:
type: basic
username: "$secrets.servicenow_user"
password: "$secrets.servicenow_password"
resources:
- name: incidents
path: "/table/incident"
operations:
- name: create-incident
method: POST
Queries Salesforce for institutional subscriptions expiring within 90 days, enriches contacts via Scopus, and triggers a HubSpot renewal email campaign.
naftiko: "0.5"
info:
label: "Subscription Renewal Campaign"
description: "Queries Salesforce for institutional subscriptions expiring within 90 days, enriches contacts via Scopus, and triggers a HubSpot renewal email campaign."
tags:
- sales
- crm
- marketing
- salesforce
- hubspot
- scopus
- renewal
capability:
exposes:
- type: mcp
namespace: renewal-marketing
port: 8080
tools:
- name: trigger-renewal-campaign
description: "Given a journal product code and renewal window in days, query Salesforce for expiring subscriptions, and enroll matching contacts in a HubSpot renewal workflow. Use 90 days before subscription end date."
inputParameters:
- name: product_code
in: body
type: string
description: "Journal bundle product code (e.g., FREEDOM-COLLECTION-2026)."
- name: days_until_expiry
in: body
type: integer
description: "Number of days before expiry to target (e.g., 90)."
steps:
- name: get-expiring-subscriptions
type: call
call: salesforce.query-expiring-subscriptions
with:
product_code: "{{product_code}}"
days_until_expiry: "{{days_until_expiry}}"
- name: enroll-hubspot
type: call
call: hubspot.enroll-contacts-in-workflow
with:
workflow_id: "$secrets.hubspot_renewal_workflow_id"
contact_emails: "{{get-expiring-subscriptions.contact_emails}}"
consumes:
- type: http
namespace: salesforce
baseUri: "https://elsevier.my.salesforce.com/services/data/v58.0"
authentication:
type: bearer
token: "$secrets.salesforce_token"
resources:
- name: subscriptions
path: "/query"
inputParameters:
- name: product_code
in: query
- name: days_until_expiry
in: query
operations:
- name: query-expiring-subscriptions
method: GET
- type: http
namespace: hubspot
baseUri: "https://api.hubapi.com/marketing/v3"
authentication:
type: bearer
token: "$secrets.hubspot_token"
resources:
- name: workflow-enrollments
path: "/workflows/{{workflow_id}}/enrollments"
inputParameters:
- name: workflow_id
in: path
operations:
- name: enroll-contacts-in-workflow
method: POST
Triggers a Tableau Server extract refresh for the journal metrics dashboard and notifies the editorial team via Microsoft Teams.
naftiko: "0.5"
info:
label: "Tableau Journal Metrics Refresh"
description: "Triggers a Tableau Server extract refresh for the journal metrics dashboard and notifies the editorial team via Microsoft Teams."
tags:
- analytics
- publishing
- tableau
- microsoft-teams
capability:
exposes:
- type: mcp
namespace: bi-ops
port: 8080
tools:
- name: refresh-journal-metrics
description: "Trigger a Tableau workbook refresh for journal metrics and notify editorial via Teams."
inputParameters:
- name: workbook_id
in: body
type: string
description: "Tableau workbook ID."
steps:
- name: trigger-refresh
type: call
call: tableau.refresh-workbook
with:
workbook_id: "{{workbook_id}}"
- name: notify-editorial
type: call
call: msteams.post-channel-message
with:
channel_id: "editorial-analytics"
text: "Journal metrics dashboard refresh triggered. Job: {{trigger-refresh.job.id}}"
consumes:
- type: http
namespace: tableau
baseUri: "https://tableau.elsevier.com/api/3.21"
authentication:
type: bearer
token: "$secrets.tableau_token"
resources:
- name: workbooks
path: "/sites/{{site_id}}/workbooks/{{workbook_id}}/refresh"
inputParameters:
- name: workbook_id
in: path
operations:
- name: refresh-workbook
method: POST
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/{{team_id}}/channels/{{channel_id}}/messages"
inputParameters:
- name: channel_id
in: path
operations:
- name: post-channel-message
method: POST
Queries Tableau Server for dashboard view counts by department, aggregates in Snowflake, and sends a weekly digest report to stakeholders via Microsoft Teams.
naftiko: "0.5"
info:
label: "Tableau Usage Digest"
description: "Queries Tableau Server for dashboard view counts by department, aggregates in Snowflake, and sends a weekly digest report to stakeholders via Microsoft Teams."
tags:
- analytics
- reporting
- tableau
- snowflake
- msteams
capability:
exposes:
- type: mcp
namespace: analytics-reporting
port: 8080
tools:
- name: digest-tableau-usage
description: "Given a Tableau site name and date range, fetch workbook view stats, write aggregated counts to Snowflake, and post a usage digest to the analytics Teams channel. Use for weekly BI adoption reporting."
inputParameters:
- name: tableau_site
in: body
type: string
description: "Tableau Server site name (e.g., elsevier-analytics)."
- name: start_date
in: body
type: string
description: "Report start date in ISO 8601 format (YYYY-MM-DD)."
- name: end_date
in: body
type: string
description: "Report end date in ISO 8601 format (YYYY-MM-DD)."
steps:
- name: get-view-stats
type: call
call: tableau.get-view-stats
with:
site: "{{tableau_site}}"
start_date: "{{start_date}}"
end_date: "{{end_date}}"
- name: write-to-snowflake
type: call
call: snowflake.insert-usage-row
with:
site: "{{tableau_site}}"
total_views: "{{get-view-stats.total_views}}"
start_date: "{{start_date}}"
end_date: "{{end_date}}"
- name: post-digest
type: call
call: msteams.send-message
with:
channel: "analytics-ops"
text: "Tableau Usage {{start_date}} to {{end_date}}: {{get-view-stats.total_views}} total views across {{get-view-stats.workbook_count}} workbooks."
consumes:
- type: http
namespace: tableau
baseUri: "https://elsevier-tableau.online.tableau.com/api/2.8"
authentication:
type: bearer
token: "$secrets.tableau_token"
resources:
- name: view-stats
path: "/sites/{{site}}/views/usage"
inputParameters:
- name: site
in: path
- name: start_date
in: query
- name: end_date
in: query
operations:
- name: get-view-stats
method: GET
- type: http
namespace: snowflake
baseUri: "https://elsevier.snowflakecomputing.com/api/v2"
authentication:
type: bearer
token: "$secrets.snowflake_token"
resources:
- name: usage-table
path: "/statements"
operations:
- name: insert-usage-row
method: POST
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/analytics/channels/general/messages"
operations:
- name: send-message
method: POST
Triggers a Terraform Cloud apply run for infrastructure provisioning and notifies the infra team via Slack.
naftiko: "0.5"
info:
label: "Terraform Infrastructure Provisioning"
description: "Triggers a Terraform Cloud apply run for infrastructure provisioning and notifies the infra team via Slack."
tags:
- infrastructure
- iac
- terraform
- slack
capability:
exposes:
- type: mcp
namespace: infra-ops
port: 8080
tools:
- name: provision-infrastructure
description: "Given a Terraform workspace ID, trigger an apply run and notify Slack."
inputParameters:
- name: workspace_id
in: body
type: string
description: "Terraform Cloud workspace ID."
steps:
- name: create-run
type: call
call: terraform.create-run
with:
workspace_id: "{{workspace_id}}"
- name: notify-infra
type: call
call: slack.post-message
with:
channel: "infra-ops"
text: "Terraform run triggered: workspace {{workspace_id}}, run {{create-run.id}}"
consumes:
- type: http
namespace: terraform
baseUri: "https://app.terraform.io/api/v2"
authentication:
type: bearer
token: "$secrets.terraform_token"
resources:
- name: runs
path: "/runs"
operations:
- name: create-run
method: POST
- type: http
namespace: slack
baseUri: "https://slack.com/api"
authentication:
type: bearer
token: "$secrets.slack_bot_token"
resources:
- name: messages
path: "/chat.postMessage"
operations:
- name: post-message
method: POST
Retrieves an employee's PTO and sick leave balances from Workday by employee ID.
naftiko: "0.5"
info:
label: "Workday Absence Balance Lookup"
description: "Retrieves an employee's PTO and sick leave balances from Workday by employee ID."
tags:
- hr
- leave-management
- workday
capability:
exposes:
- type: mcp
namespace: hr-ops
port: 8080
tools:
- name: get-absence-balance
description: "Given a Workday employee ID, return PTO balance, sick leave balance, and next accrual date."
inputParameters:
- name: employee_id
in: body
type: string
description: "Workday employee ID."
call: workday.get-balance
with:
employee_id: "{{employee_id}}"
outputParameters:
- name: pto_balance
type: number
mapping: "$.Worker.TimeOff.PTO_Balance"
- name: sick_balance
type: number
mapping: "$.Worker.TimeOff.Sick_Balance"
consumes:
- type: http
namespace: workday
baseUri: "https://wd5-impl-services1.workday.com/ccx/service/elsevier"
authentication:
type: basic
username: "$secrets.workday_user"
password: "$secrets.workday_password"
resources:
- name: absence
path: "/Human_Resources/v40.0/Get_Workers"
operations:
- name: get-balance
method: GET
When an employee submits an absence request in Workday exceeding five days, notifies the direct manager via Teams and creates a coverage task in ServiceNow.
naftiko: "0.5"
info:
label: "Workday Absence Request Notification"
description: "When an employee submits an absence request in Workday exceeding five days, notifies the direct manager via Teams and creates a coverage task in ServiceNow."
tags:
- hr
- absence-management
- workday
- servicenow
- msteams
capability:
exposes:
- type: mcp
namespace: hr-absence
port: 8080
tools:
- name: handle-absence-request
description: "Given a Workday worker ID and absence request ID, fetch the request details, notify the manager via Teams, and open a ServiceNow task for coverage planning if the absence exceeds five days."
inputParameters:
- name: workday_worker_id
in: body
type: string
description: "Workday worker ID of the employee requesting absence."
- name: absence_request_id
in: body
type: string
description: "Workday absence request ID."
steps:
- name: get-absence-details
type: call
call: workday.get-absence-request
with:
worker_id: "{{workday_worker_id}}"
request_id: "{{absence_request_id}}"
- name: notify-manager
type: call
call: msteams.send-message
with:
recipient_upn: "{{get-absence-details.manager_email}}"
text: "Absence request submitted by {{get-absence-details.employee_name}}: {{get-absence-details.start_date}} to {{get-absence-details.end_date}} ({{get-absence-details.days}} days)."
- name: create-coverage-task
type: call
call: servicenow.create-task
with:
short_description: "Coverage planning: {{get-absence-details.employee_name}} absent {{get-absence-details.start_date}} to {{get-absence-details.end_date}}"
assignment_group: "{{get-absence-details.department}}_Managers"
consumes:
- type: http
namespace: workday
baseUri: "https://wd2-impl-services1.workday.com/ccx/api/v1"
authentication:
type: bearer
token: "$secrets.workday_token"
resources:
- name: absence-requests
path: "/workers/{{worker_id}}/absenceRequests/{{request_id}}"
inputParameters:
- name: worker_id
in: path
- name: request_id
in: path
operations:
- name: get-absence-request
method: GET
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: messages
path: "/users/{{recipient_upn}}/sendMail"
inputParameters:
- name: recipient_upn
in: path
operations:
- name: send-message
method: POST
- type: http
namespace: servicenow
baseUri: "https://elsevier.service-now.com/api/now"
authentication:
type: basic
username: "$secrets.servicenow_user"
password: "$secrets.servicenow_password"
resources:
- name: tasks
path: "/table/task"
operations:
- name: create-task
method: POST
Queries Workday for employees with incomplete benefits enrollment and sends reminders via Microsoft Graph email.
naftiko: "0.5"
info:
label: "Workday Benefits Enrollment"
description: "Queries Workday for employees with incomplete benefits enrollment and sends reminders via Microsoft Graph email."
tags:
- hr
- benefits
- workday
- microsoft-teams
capability:
exposes:
- type: mcp
namespace: hr-ops
port: 8080
tools:
- name: send-enrollment-reminders
description: "Fetch employees with pending enrollment and send reminder emails."
inputParameters:
- name: enrollment_period
in: body
type: string
description: "Enrollment period identifier."
steps:
- name: get-pending
type: call
call: workday.get-pending-enrollment
with:
period: "{{enrollment_period}}"
- name: send-reminders
type: call
call: msgraph.send-mail
with:
recipients: "{{get-pending.employee_emails}}"
subject: "Complete Your Benefits Enrollment"
body: "Please complete enrollment for {{enrollment_period}} in Workday."
consumes:
- type: http
namespace: workday
baseUri: "https://wd5-impl-services1.workday.com/ccx/service/elsevier"
authentication:
type: basic
username: "$secrets.workday_user"
password: "$secrets.workday_password"
resources:
- name: benefits
path: "/Benefits/v40.0"
operations:
- name: get-pending-enrollment
method: GET
- type: http
namespace: msgraph
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msgraph_token"
resources:
- name: mail
path: "/me/sendMail"
operations:
- name: send-mail
method: POST
When a compensation change is approved, notifies HR via Microsoft Teams.
naftiko: "0.5"
info:
label: "Workday Compensation Alert"
description: "When a compensation change is approved, notifies HR via Microsoft Teams."
tags:
- hr
- compensation
- workday
- microsoft-teams
capability:
exposes:
- type: mcp
namespace: hr-ops
port: 8080
tools:
- name: notify-comp-change
description: "Given a Workday employee ID and event ID, fetch details and notify HR via Teams."
inputParameters:
- name: employee_id
in: body
type: string
description: "Workday employee ID."
- name: event_id
in: body
type: string
description: "Compensation event ID."
steps:
- name: get-event
type: call
call: workday.get-comp-event
with:
employee_id: "{{employee_id}}"
event_id: "{{event_id}}"
- name: notify-hr
type: call
call: msteams.post-channel-message
with:
channel_id: "hr-notifications"
text: "Compensation change for {{employee_id}}: effective {{get-event.effective_date}}"
consumes:
- type: http
namespace: workday
baseUri: "https://wd5-impl-services1.workday.com/ccx/service/elsevier"
authentication:
type: basic
username: "$secrets.workday_user"
password: "$secrets.workday_password"
resources:
- name: compensation
path: "/Compensation/v40.0"
operations:
- name: get-comp-event
method: GET
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: channel-messages
path: "/teams/{{team_id}}/channels/{{channel_id}}/messages"
inputParameters:
- name: channel_id
in: path
operations:
- name: post-channel-message
method: POST
Exports a headcount snapshot by department from Workday and writes the data to Snowflake for reporting and workforce planning analysis.
naftiko: "0.5"
info:
label: "Workday Headcount Snapshot"
description: "Exports a headcount snapshot by department from Workday and writes the data to Snowflake for reporting and workforce planning analysis."
tags:
- hr
- analytics
- workday
- snowflake
- reporting
- headcount
capability:
exposes:
- type: mcp
namespace: hr-analytics
port: 8080
tools:
- name: snapshot-headcount
description: "Fetch current active headcount grouped by department and cost center from Workday, then insert a snapshot row to Snowflake. Use for monthly workforce planning data updates."
inputParameters:
- name: snapshot_date
in: body
type: string
description: "Snapshot date in ISO 8601 format (YYYY-MM-DD) to tag the record."
steps:
- name: export-workers
type: call
call: workday.export-workers
with:
status: "active"
fields: "employee_id,full_name,department,cost_center,employment_type"
- name: write-snapshot
type: call
call: snowflake.insert-headcount-snapshot
with:
snapshot_date: "{{snapshot_date}}"
records: "{{export-workers.rows}}"
consumes:
- type: http
namespace: workday
baseUri: "https://wd2-impl-services1.workday.com/ccx/api/v1"
authentication:
type: bearer
token: "$secrets.workday_token"
resources:
- name: workers-export
path: "/workers"
inputParameters:
- name: status
in: query
- name: fields
in: query
operations:
- name: export-workers
method: GET
- type: http
namespace: snowflake
baseUri: "https://elsevier.snowflakecomputing.com/api/v2"
authentication:
type: bearer
token: "$secrets.snowflake_token"
resources:
- name: headcount-snapshots
path: "/statements"
operations:
- name: insert-headcount-snapshot
method: POST
Creates a position requisition in Workday and notifies the recruiting team via Slack.
naftiko: "0.5"
info:
label: "Workday New Position Requisition"
description: "Creates a position requisition in Workday and notifies the recruiting team via Slack."
tags:
- hr
- recruiting
- workday
- slack
capability:
exposes:
- type: mcp
namespace: recruiting-ops
port: 8080
tools:
- name: create-requisition
description: "Create a Workday position requisition and notify the recruiting Slack channel."
inputParameters:
- name: job_title
in: body
type: string
description: "Job title."
- name: department
in: body
type: string
description: "Department."
steps:
- name: create-req
type: call
call: workday.create-requisition
with:
title: "{{job_title}}"
department: "{{department}}"
- name: notify-recruiting
type: call
call: slack.post-message
with:
channel: "recruiting"
text: "New requisition: {{job_title}} in {{department}} | ID: {{create-req.requisition_id}}"
consumes:
- type: http
namespace: workday
baseUri: "https://wd5-impl-services1.workday.com/ccx/service/elsevier"
authentication:
type: basic
username: "$secrets.workday_user"
password: "$secrets.workday_password"
resources:
- name: requisitions
path: "/Recruiting/v40.0"
operations:
- name: create-requisition
method: POST
- type: http
namespace: slack
baseUri: "https://slack.com/api"
authentication:
type: bearer
token: "$secrets.slack_bot_token"
resources:
- name: messages
path: "/chat.postMessage"
operations:
- name: post-message
method: POST
Retrieves manager and direct reports for a Workday employee by employee ID.
naftiko: "0.5"
info:
label: "Workday Org Chart Lookup"
description: "Retrieves manager and direct reports for a Workday employee by employee ID."
tags:
- hr
- workforce
- workday
capability:
exposes:
- type: mcp
namespace: hr-ops
port: 8080
tools:
- name: get-org-chart
description: "Given a Workday employee ID, return manager name and direct reports list."
inputParameters:
- name: employee_id
in: body
type: string
description: "Workday employee ID."
call: workday.get-worker
with:
employee_id: "{{employee_id}}"
outputParameters:
- name: manager
type: string
mapping: "$.Worker.Manager.Name"
- name: direct_reports
type: array
mapping: "$.Worker.DirectReports[*].Name"
consumes:
- type: http
namespace: workday
baseUri: "https://wd5-impl-services1.workday.com/ccx/service/elsevier"
authentication:
type: basic
username: "$secrets.workday_user"
password: "$secrets.workday_password"
resources:
- name: workers
path: "/Human_Resources/v40.0/Get_Workers"
operations:
- name: get-worker
method: GET
When an employee's role changes in Workday, updates their Salesforce user profile, adjusts GitHub team membership, and notifies the manager via Teams.
naftiko: "0.5"
info:
label: "Workday Role Change Propagation"
description: "When an employee's role changes in Workday, updates their Salesforce user profile, adjusts GitHub team membership, and notifies the manager via Teams."
tags:
- hr
- identity
- workday
- salesforce
- github
- msteams
- role-change
capability:
exposes:
- type: mcp
namespace: hr-role-change
port: 8080
tools:
- name: propagate-role-change
description: "Given a Workday employee ID, old role, and new role, update Salesforce user permissions, adjust GitHub team membership, and notify the manager. Use on confirmed Workday position change events."
inputParameters:
- name: workday_employee_id
in: body
type: string
description: "Workday worker ID of the employee changing roles."
- name: new_role
in: body
type: string
description: "New job title or role code as defined in Workday."
steps:
- name: get-worker
type: call
call: workday.get-worker
with:
worker_id: "{{workday_employee_id}}"
- name: update-salesforce-user
type: call
call: salesforce.patch-user
with:
email: "{{get-worker.email}}"
Title: "{{new_role}}"
Department: "{{get-worker.department}}"
- name: update-github-team
type: call
call: github.update-team-membership
with:
org: "elsevier"
team_slug: "{{get-worker.department}}"
username: "{{get-worker.github_username}}"
role: "member"
- name: notify-manager
type: call
call: msteams.send-message
with:
recipient_upn: "{{get-worker.manager_email}}"
text: "Role change processed for {{get-worker.full_name}}: now {{new_role}}. Salesforce and GitHub updated."
consumes:
- type: http
namespace: workday
baseUri: "https://wd2-impl-services1.workday.com/ccx/api/v1"
authentication:
type: bearer
token: "$secrets.workday_token"
resources:
- name: workers
path: "/workers/{{worker_id}}"
inputParameters:
- name: worker_id
in: path
operations:
- name: get-worker
method: GET
- type: http
namespace: salesforce
baseUri: "https://elsevier.my.salesforce.com/services/data/v58.0"
authentication:
type: bearer
token: "$secrets.salesforce_token"
resources:
- name: users
path: "/sobjects/User"
operations:
- name: patch-user
method: PATCH
- type: http
namespace: github
baseUri: "https://api.github.com"
authentication:
type: bearer
token: "$secrets.github_token"
resources:
- name: team-members
path: "/orgs/{{org}}/teams/{{team_slug}}/memberships/{{username}}"
inputParameters:
- name: org
in: path
- name: team_slug
in: path
- name: username
in: path
operations:
- name: update-team-membership
method: PUT
- type: http
namespace: msteams
baseUri: "https://graph.microsoft.com/v1.0"
authentication:
type: bearer
token: "$secrets.msteams_token"
resources:
- name: messages
path: "/users/{{recipient_upn}}/sendMail"
inputParameters:
- name: recipient_upn
in: path
operations:
- name: send-message
method: POST
Retrieves a Zendesk author support ticket by ID, returning subject, status, and priority.
naftiko: "0.5"
info:
label: "Zendesk Author Support Ticket Lookup"
description: "Retrieves a Zendesk author support ticket by ID, returning subject, status, and priority."
tags:
- support
- publishing
- zendesk
capability:
exposes:
- type: mcp
namespace: author-support
port: 8080
tools:
- name: get-author-ticket
description: "Given a Zendesk ticket ID, return subject, status, priority, and requester email."
inputParameters:
- name: ticket_id
in: body
type: string
description: "Zendesk ticket ID."
call: zendesk.get-ticket
with:
ticket_id: "{{ticket_id}}"
outputParameters:
- name: subject
type: string
mapping: "$.ticket.subject"
- name: status
type: string
mapping: "$.ticket.status"
- name: priority
type: string
mapping: "$.ticket.priority"
consumes:
- type: http
namespace: zendesk
baseUri: "https://elsevier.zendesk.com/api/v2"
authentication:
type: bearer
token: "$secrets.zendesk_token"
resources:
- name: tickets
path: "/tickets/{{ticket_id}}.json"
inputParameters:
- name: ticket_id
in: path
operations:
- name: get-ticket
method: GET
Fetches Zoom webinar registrations and syncs attendee data to HubSpot for follow-up marketing.
naftiko: "0.5"
info:
label: "Zoom Webinar Registration Sync"
description: "Fetches Zoom webinar registrations and syncs attendee data to HubSpot for follow-up marketing."
tags:
- marketing
- events
- zoom
- hubspot
capability:
exposes:
- type: mcp
namespace: events-ops
port: 8080
tools:
- name: sync-webinar-registrants
description: "Given a Zoom webinar ID, fetch registrants and sync to HubSpot contacts."
inputParameters:
- name: webinar_id
in: body
type: string
description: "Zoom webinar ID."
steps:
- name: get-registrants
type: call
call: zoom.list-registrants
with:
webinar_id: "{{webinar_id}}"
- name: sync-to-hubspot
type: call
call: hubspot.batch-create-contacts
with:
contacts: "{{get-registrants.registrants}}"
consumes:
- type: http
namespace: zoom
baseUri: "https://api.zoom.us/v2"
authentication:
type: bearer
token: "$secrets.zoom_token"
resources:
- name: registrants
path: "/webinars/{{webinar_id}}/registrants"
inputParameters:
- name: webinar_id
in: path
operations:
- name: list-registrants
method: GET
- type: http
namespace: hubspot
baseUri: "https://api.hubapi.com"
authentication:
type: bearer
token: "$secrets.hubspot_token"
resources:
- name: contacts
path: "/crm/v3/objects/contacts/batch/create"
operations:
- name: batch-create-contacts
method: POST