<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.onqpr.com/pa/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=TeeHiet</id>
	<title>QPR ProcessAnalyzer Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.onqpr.com/pa/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=TeeHiet"/>
	<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php/Special:Contributions/TeeHiet"/>
	<updated>2026-05-11T15:40:06Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.1</generator>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_BPMN_Editor&amp;diff=28285</id>
		<title>QPR ProcessAnalyzer BPMN Editor</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_BPMN_Editor&amp;diff=28285"/>
		<updated>2026-05-06T09:05:07Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63956&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page describes components that are used for editing BPMN models and viewing conformance analysis results. Note that for dashboards that use BPMN and conformance functionality, you need to create a variable &#039;&#039;&#039;designModel&#039;&#039;&#039; with behavior &#039;&#039;Stored&#039;&#039; (in the &#039;&#039;Dashboard Properties&#039;&#039; in &#039;&#039;Variables&#039;&#039; tab), so that the dashboard is able to store the defined BPMN model. The other option is to define the [[QPR_MEA_Integration#MEA_Connection_String|MEA Connection String]], so that the BPMN model can be stored in the QPR ProcessDesigner repository. Note also that the BPMN editor only allows to add BPMN elements that are supported by the conformance checking functionality.&lt;br /&gt;
&lt;br /&gt;
== BPMN Editor ==&lt;br /&gt;
The &#039;&#039;&#039;BPMN Editor&#039;&#039;&#039; analyzes process mining data with the help of a designed BPMN process model. You can for example:&lt;br /&gt;
* See process mining KPI&#039;s and statistics calculated on the fly top of the BPMN diagram during the modeling the BPMN&lt;br /&gt;
* Run conformance analysis using the designed BPMN model&lt;br /&gt;
* Filter data directly from the BPMN diagram&lt;br /&gt;
&lt;br /&gt;
The BPMN diagram can be drawn from scratch, opened from QPR ProcessDesigner repository via QPR MEA Web Service, or imported from a BPMN 2.0 XML file. The ready diagram can be saved to the QPR ProcessDesigner repository or exported to a BPMN 2.0 XML file.&lt;br /&gt;
&lt;br /&gt;
BPMN diagrams are created by dragging items from the tool palette. Start event, end event, task and gateways are the most used elements. When you add a BPMN task to the canvas, all event types are shown in a list next to the task, and an event type can be selected to match it with the created task. When the task is added, KPI values are calculated and shown in the blue background. When flows are added, KPI values are calculated and shown for them, too. By clicking the KPI in the top right legend, the KPI value is hidden, to make the BPMN diagram more readable if there are lots of items.&lt;br /&gt;
&lt;br /&gt;
When you select a BPMN task, it suggest to create a filter. In the dropdown list you can select which type of filter is created. When you select a BPMN flow, it also suggest to create a filter.&lt;br /&gt;
&lt;br /&gt;
You can create a filter to get only the conforming or nonconforming cases based on the current BPMN model by selecting &#039;&#039;&#039;Include conforming cases&#039;&#039;&#039; or &#039;&#039;&#039;Include nonconforming cases&#039;&#039;&#039; from the context menu.&lt;br /&gt;
&lt;br /&gt;
=== Auto-creating BPMN Diagram from Eventlog ===&lt;br /&gt;
BPMN editor&#039;s context menu has the &#039;&#039;&#039;Auto-create diagram&#039;&#039;&#039; option which will automatically create and layout a fully conforming BPMN diagram from the filtered eventlog. The created diagram contains paths for all the process variations in the filtered eventlog. The diagram will have one start element and one end element, all the event types appear as BPMN tasks in the diagram. The auto-creation intelligently identifies the types of gateways, using either the exclusive or parallel gateways. Parallel gateways indicate that there are activities occurring simultaneously in the process that are typically independent of each other.&lt;br /&gt;
&lt;br /&gt;
Eventlogs often contain a large number of process variations, even in smaller datasets. Capturing every variation in a single BPMN diagram can quickly lead to a model that is overly complex and difficult to interpret. A practical approach is to first filter the eventlog to include only the cases that represent the desired variations or process behaviors. Using the variation filter is typically the easiest way to select the process behavior you want to include to the BPMN diagram. You may need to iterate a few times by adjusting filters and regenerating the diagram to arrive at a BPMN model that represents the desired process flow. If the auto-created diagram still does not fully meet your needs, you can always continue refining it manually using the BPMN editor.&lt;br /&gt;
&lt;br /&gt;
The auto-creation feature is available for the Snowflake models, and it uses the expression language&#039;s [[Generic_Functions_in_QPR_ProcessAnalyzer#:~:text=ToBpmn|ToBpmn]] function which generates the BPMN diagram in the Snowflake by calling a Python function powered by the PM4Py library (https://processintelligence.solutions/pm4py). The function is executed in the same Snowflake ODBC connection where the eventlog data is located. To use the auto-creation feature, the required Python libraries need to be deployed to Snowflake as instructed [[Snowflake_Connection_Configuration#Enable_auto-create_BPMN_diagrams|here]].&lt;br /&gt;
&lt;br /&gt;
=== Adding tasks and flows, and Deleting Diagram ===&lt;br /&gt;
There are following functions available:&lt;br /&gt;
* &#039;&#039;&#039;Add tasks and flows&#039;&#039;&#039; will create a BPMN model that is the same as the as-is model. Thus, the as-is model will conform perfectly to the design model. After the tasks and flows are created, you can edit the design model and remove the events and flows that shouldn&#039;t occur in the process. Note however, that the amount of flows that is created can easily be overwhelming. To overcome this, you can first filter out those events and flows that shouldn&#039;t occur in the desired process and then use the auto-create. After creating the design model, you can remove the filter to check the conformance of the whole model. Note that due to performance reasons, the number of flows in the auto-generated model is limited to 1000.&lt;br /&gt;
* &#039;&#039;&#039;Add tasks only&#039;&#039;&#039; will generate only the tasks without any flows. The result is a model that needs to be filled with flows to be a valid BPMN model.&lt;br /&gt;
* &#039;&#039;&#039;Delete diagram&#039;&#039;&#039; will delete the current diagram and start from an empty canvas.&lt;br /&gt;
&lt;br /&gt;
=== Opening and Saving a Diagram in the Repository ===&lt;br /&gt;
To open a diagram from the repository:&lt;br /&gt;
# Click the &#039;&#039;&#039;Open diagram from repository&#039;&#039;&#039; button on the bottom left of the BPMN Editor. The Open Diagram from Repository dialog will open.&lt;br /&gt;
# In the &#039;&#039;&#039;Process Models&#039;&#039;&#039; hierarchy, select a BPMN model.&lt;br /&gt;
# In the &#039;&#039;&#039;Diagrams&#039;&#039;&#039; hierarchy, select a BPMN diagram.&lt;br /&gt;
# Click &#039;&#039;&#039;Open&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
To save a diagram to the repository:&lt;br /&gt;
# Click the &#039;&#039;&#039;Save diagram to repository&#039;&#039;&#039; button on the bottom left of the BPMN Editor. The Save Diagram to Repository dialog will open.&lt;br /&gt;
# In the &#039;&#039;&#039;Process Models&#039;&#039;&#039; hierarchy, select a BPMN model.&lt;br /&gt;
# In &#039;&#039;&#039;Diagrams&#039;&#039;&#039; hierarchy, select the target BPMN diagram location.&lt;br /&gt;
# Click &#039;&#039;&#039;Save&#039;&#039;&#039;.&lt;br /&gt;
Note that a BPMN diagram may contain an entire diagram hierarchy. When a BPMN diagram is saved, the entire diagram hierarchy is replaced at the level where the saving is made.&lt;br /&gt;
&lt;br /&gt;
=== Creating a New Diagram to the Repository ===&lt;br /&gt;
A new diagram can be created to the repository as follows:&lt;br /&gt;
# Click the &#039;&#039;&#039;Save diagram to repository&#039;&#039;&#039; button on the bottom left of the BPMN Editor. The Save Diagram to Repository dialog will open.&lt;br /&gt;
# Select the diagram under which the new diagram should be created.&lt;br /&gt;
# Click &#039;&#039;&#039;New Diagram&#039;&#039;&#039;.&lt;br /&gt;
# Enter the diagram name in the dialog that opens. A duplicate name cannot be created on the same diagram level.&lt;br /&gt;
# Click &#039;&#039;&#039;Create&#039;&#039;&#039;.&lt;br /&gt;
After creation, the new diagram is added under the previously selected diagram.&lt;br /&gt;
&lt;br /&gt;
=== Renaming or Deleting a Diagram from the Repository ===&lt;br /&gt;
A diagram can be renamed or deleted from the repository as follows:&lt;br /&gt;
# Click the &#039;&#039;&#039;Save diagram to repository&#039;&#039;&#039; button on the bottom left of the BPMN Editor. The Save Diagram to Repository dialog will open.&lt;br /&gt;
# Select the diagram you want to rename or delete.&lt;br /&gt;
# Click either &#039;&#039;&#039;Rename Diagram&#039;&#039;&#039; or &#039;&#039;&#039;Delete Diagram&#039;&#039;&#039;.&lt;br /&gt;
# Depending on the chosen action, give a new name for the diagram and click &#039;&#039;&#039;Rename&#039;&#039;&#039; or click &#039;&#039;&#039;Delete&#039;&#039;&#039; in the confirmation dialog.&lt;br /&gt;
&lt;br /&gt;
=== Reports Selectable in BPMN Diagram ===&lt;br /&gt;
There are also following reports available for in-memory models:&lt;br /&gt;
* &#039;&#039;&#039;Duration distribution between tasks&#039;&#039;&#039; (select 2 tasks)&lt;br /&gt;
* &#039;&#039;&#039;Flow duration distribution&#039;&#039;&#039; (select 1 flow)&lt;br /&gt;
* &#039;&#039;&#039;Task occurrences across time&#039;&#039;&#039; (select 1 task)&lt;br /&gt;
* &#039;&#039;&#039;Task repetition in cases&#039;&#039;&#039; (select 1 task)&lt;br /&gt;
* You can export the BPMN diagram contents as a flat list by clicking the &#039;&#039;&#039;Export all BPMN elements as CSV&#039;&#039;&#039;.&lt;br /&gt;
* You can export a list of BPMN elements in the order that they appear in the flow by clicking the &#039;&#039;&#039;Export element order&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== KPI&#039;s on BPMN Diagram===&lt;br /&gt;
The following KPI&#039;s are shown:&lt;br /&gt;
* &#039;&#039;&#039;Cases having task&#039;&#039;&#039;: Number of cases in the process mining data, that have this task (=event type).&lt;br /&gt;
* &#039;&#039;&#039;Task occurred&#039;&#039;&#039;: Number of times this type of event has occurred in the process mining data. This number is the same or larger than the Cases having task count. If it&#039;s larger, the event has occurred more than once in a case (looping, repetition).&lt;br /&gt;
&lt;br /&gt;
Flow has a different meaning in the BPMN diagram than in the traditional process mining diagram. In the process mining diagram, a flow is &#039;&#039;direct&#039;&#039; transition between two events. This means that no other event has occurred between the start and end event of the flow. In the BPMN diagram. Following KPI&#039;s for flows are shown for in-memory models (there are no flow KPI&#039;s for Snowflake models):&lt;br /&gt;
* &#039;&#039;&#039;Flow median duration&#039;&#039;&#039;: Median duration from the task event of the flow to the end event of the flow.&lt;br /&gt;
* &#039;&#039;&#039;Flow occurred&#039;&#039;&#039;: Number of times the flow has occurred in all cases. The BPMN flow occurs when in the case there occurs the starting event and that is followed by the end event at any point in the case.&lt;br /&gt;
* &#039;&#039;&#039;Other events between&#039;&#039;&#039;: Number of events that has occurred between the starting and ending event in the flow.&lt;br /&gt;
&lt;br /&gt;
== Design Model Selector ==&lt;br /&gt;
In addition to the &#039;&#039;BPMN Editor&#039;&#039;, there is also a &#039;&#039;&#039;Design Model Selector&#039;&#039;&#039; component available, which adds a button to the dashboard for opening an overlay BPMN editor. The Design Model Selector is better when there is no space in the dashboard to show the BPMN model.&lt;br /&gt;
&lt;br /&gt;
The Design Model Selector validates the BPMN model when the editor is closed, so invalid BPMN models cannot be saved.&lt;br /&gt;
&lt;br /&gt;
== Conformance Statistics ==&lt;br /&gt;
&#039;&#039;&#039;Conformance Statistics&#039;&#039;&#039; visualization shows an overview of how many cases are conformant and deviating (both as absolute case count and percentage of total cases). In addition, the Conformance Statistics component shown average duration of cases and average number of events per case in both the conformant and deviating cases groups. The used BPMN model is stored in the &#039;&#039;designModel&#039;&#039; variable in the context of the conformance statistics visualization.&lt;br /&gt;
&lt;br /&gt;
[[Category: QPR ProcessAnalyzer]]&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_BPMN_Editor&amp;diff=28284</id>
		<title>QPR ProcessAnalyzer BPMN Editor</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_BPMN_Editor&amp;diff=28284"/>
		<updated>2026-05-06T08:24:13Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63956&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page describes components that are used for editing BPMN models and viewing conformance analysis results. Note that for dashboards that use BPMN and conformance functionality, you need to create a variable &#039;&#039;&#039;designModel&#039;&#039;&#039; with behavior &#039;&#039;Stored&#039;&#039; (in the &#039;&#039;Dashboard Properties&#039;&#039; in &#039;&#039;Variables&#039;&#039; tab), so that the dashboard is able to store the defined BPMN model. Note also that the BPMN editor only allows to add BPMN elements that are supported by the conformance checking functionality.&lt;br /&gt;
&lt;br /&gt;
== BPMN Editor ==&lt;br /&gt;
The &#039;&#039;&#039;BPMN Editor&#039;&#039;&#039; analyzes process mining data with the help of a designed BPMN process model. You can for example:&lt;br /&gt;
* See process mining KPI&#039;s and statistics calculated on the fly top of the BPMN diagram during the modeling the BPMN&lt;br /&gt;
* Run conformance analysis using the designed BPMN model&lt;br /&gt;
* Filter data directly from the BPMN diagram&lt;br /&gt;
&lt;br /&gt;
The BPMN diagram can be drawn from scratch, opened from QPR ProcessDesigner repository via QPR MEA Web Service, or imported from a BPMN 2.0 XML file. The ready diagram can be saved to the QPR ProcessDesigner repository or exported to a BPMN 2.0 XML file.&lt;br /&gt;
&lt;br /&gt;
BPMN diagrams are created by dragging items from the tool palette. Start event, end event, task and gateways are the most used elements. When you add a BPMN task to the canvas, all event types are shown in a list next to the task, and an event type can be selected to match it with the created task. When the task is added, KPI values are calculated and shown in the blue background. When flows are added, KPI values are calculated and shown for them, too. By clicking the KPI in the top right legend, the KPI value is hidden, to make the BPMN diagram more readable if there are lots of items.&lt;br /&gt;
&lt;br /&gt;
When you select a BPMN task, it suggest to create a filter. In the dropdown list you can select which type of filter is created. When you select a BPMN flow, it also suggest to create a filter.&lt;br /&gt;
&lt;br /&gt;
You can create a filter to get only the conforming or nonconforming cases based on the current BPMN model by selecting &#039;&#039;&#039;Include conforming cases&#039;&#039;&#039; or &#039;&#039;&#039;Include nonconforming cases&#039;&#039;&#039; from the context menu.&lt;br /&gt;
&lt;br /&gt;
=== Auto-creating BPMN Diagram from Eventlog ===&lt;br /&gt;
BPMN editor&#039;s context menu has the &#039;&#039;&#039;Auto-create diagram&#039;&#039;&#039; option which will automatically create and layout a fully conforming BPMN diagram from the filtered eventlog. The created diagram contains paths for all the process variations in the filtered eventlog. The diagram will have one start element and one end element, all the event types appear as BPMN tasks in the diagram. The auto-creation intelligently identifies the types of gateways, using either the exclusive or parallel gateways. Parallel gateways indicate that there are activities occurring simultaneously in the process that are typically independent of each other.&lt;br /&gt;
&lt;br /&gt;
Eventlogs often contain a large number of process variations, even in smaller datasets. Capturing every variation in a single BPMN diagram can quickly lead to a model that is overly complex and difficult to interpret. A practical approach is to first filter the eventlog to include only the cases that represent the desired variations or process behaviors. Using the variation filter is typically the easiest way to select the process behavior you want to include to the BPMN diagram. You may need to iterate a few times by adjusting filters and regenerating the diagram to arrive at a BPMN model that represents the desired process flow. If the auto-created diagram still does not fully meet your needs, you can always continue refining it manually using the BPMN editor.&lt;br /&gt;
&lt;br /&gt;
The auto-creation feature is available for the Snowflake models, and it uses the expression language&#039;s [[Generic_Functions_in_QPR_ProcessAnalyzer#:~:text=ToBpmn|ToBpmn]] function which generates the BPMN diagram in the Snowflake by calling a Python function powered by the PM4Py library (https://processintelligence.solutions/pm4py). The function is executed in the same Snowflake ODBC connection where the eventlog data is located. To use the auto-creation feature, the required Python libraries need to be deployed to Snowflake as instructed [[Snowflake_Connection_Configuration#Enable_auto-create_BPMN_diagrams|here]].&lt;br /&gt;
&lt;br /&gt;
=== Adding tasks and flows, and Deleting Diagram ===&lt;br /&gt;
There are following functions available:&lt;br /&gt;
* &#039;&#039;&#039;Add tasks and flows&#039;&#039;&#039; will create a BPMN model that is the same as the as-is model. Thus, the as-is model will conform perfectly to the design model. After the tasks and flows are created, you can edit the design model and remove the events and flows that shouldn&#039;t occur in the process. Note however, that the amount of flows that is created can easily be overwhelming. To overcome this, you can first filter out those events and flows that shouldn&#039;t occur in the desired process and then use the auto-create. After creating the design model, you can remove the filter to check the conformance of the whole model. Note that due to performance reasons, the number of flows in the auto-generated model is limited to 1000.&lt;br /&gt;
* &#039;&#039;&#039;Add tasks only&#039;&#039;&#039; will generate only the tasks without any flows. The result is a model that needs to be filled with flows to be a valid BPMN model.&lt;br /&gt;
* &#039;&#039;&#039;Delete diagram&#039;&#039;&#039; will delete the current diagram and start from an empty canvas.&lt;br /&gt;
&lt;br /&gt;
=== Opening and Saving a Diagram in the Repository ===&lt;br /&gt;
To open a diagram from the repository:&lt;br /&gt;
# Click the &#039;&#039;&#039;Open diagram from repository&#039;&#039;&#039; button on the bottom left of the BPMN Editor. The Open Diagram from Repository dialog will open.&lt;br /&gt;
# In the &#039;&#039;&#039;Process Models&#039;&#039;&#039; hierarchy, select a BPMN model.&lt;br /&gt;
# In the &#039;&#039;&#039;Diagrams&#039;&#039;&#039; hierarchy, select a BPMN diagram.&lt;br /&gt;
# Click &#039;&#039;&#039;Open&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
To save a diagram to the repository:&lt;br /&gt;
# Click the &#039;&#039;&#039;Save diagram to repository&#039;&#039;&#039; button on the bottom left of the BPMN Editor. The Save Diagram to Repository dialog will open.&lt;br /&gt;
# In the &#039;&#039;&#039;Process Models&#039;&#039;&#039; hierarchy, select a BPMN model.&lt;br /&gt;
# In &#039;&#039;&#039;Diagrams&#039;&#039;&#039; hierarchy, select the target BPMN diagram location.&lt;br /&gt;
# Click &#039;&#039;&#039;Save&#039;&#039;&#039;.&lt;br /&gt;
Note that a BPMN diagram may contain an entire diagram hierarchy. When a BPMN diagram is saved, the entire diagram hierarchy is replaced at the level where the saving is made.&lt;br /&gt;
&lt;br /&gt;
=== Creating a New Diagram to the Repository ===&lt;br /&gt;
A new diagram can be created to the repository as follows:&lt;br /&gt;
# Click the &#039;&#039;&#039;Save diagram to repository&#039;&#039;&#039; button on the bottom left of the BPMN Editor. The Save Diagram to Repository dialog will open.&lt;br /&gt;
# Select the diagram under which the new diagram should be created.&lt;br /&gt;
# Click &#039;&#039;&#039;New Diagram&#039;&#039;&#039;.&lt;br /&gt;
# Enter the diagram name in the dialog that opens. A duplicate name cannot be created on the same diagram level.&lt;br /&gt;
# Click &#039;&#039;&#039;Create&#039;&#039;&#039;.&lt;br /&gt;
After creation, the new diagram is added under the previously selected diagram.&lt;br /&gt;
&lt;br /&gt;
=== Renaming or Deleting a Diagram from the Repository ===&lt;br /&gt;
A diagram can be renamed or deleted from the repository as follows:&lt;br /&gt;
# Click the &#039;&#039;&#039;Save diagram to repository&#039;&#039;&#039; button on the bottom left of the BPMN Editor. The Save Diagram to Repository dialog will open.&lt;br /&gt;
# Select the diagram you want to rename or delete.&lt;br /&gt;
# Click either &#039;&#039;&#039;Rename Diagram&#039;&#039;&#039; or &#039;&#039;&#039;Delete Diagram&#039;&#039;&#039;.&lt;br /&gt;
# Depending on the chosen action, give a new name for the diagram and click &#039;&#039;&#039;Rename&#039;&#039;&#039; or click &#039;&#039;&#039;Delete&#039;&#039;&#039; in the confirmation dialog.&lt;br /&gt;
&lt;br /&gt;
=== Reports Selectable in BPMN Diagram ===&lt;br /&gt;
There are also following reports available for in-memory models:&lt;br /&gt;
* &#039;&#039;&#039;Duration distribution between tasks&#039;&#039;&#039; (select 2 tasks)&lt;br /&gt;
* &#039;&#039;&#039;Flow duration distribution&#039;&#039;&#039; (select 1 flow)&lt;br /&gt;
* &#039;&#039;&#039;Task occurrences across time&#039;&#039;&#039; (select 1 task)&lt;br /&gt;
* &#039;&#039;&#039;Task repetition in cases&#039;&#039;&#039; (select 1 task)&lt;br /&gt;
* You can export the BPMN diagram contents as a flat list by clicking the &#039;&#039;&#039;Export all BPMN elements as CSV&#039;&#039;&#039;.&lt;br /&gt;
* You can export a list of BPMN elements in the order that they appear in the flow by clicking the &#039;&#039;&#039;Export element order&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== KPI&#039;s on BPMN Diagram===&lt;br /&gt;
The following KPI&#039;s are shown:&lt;br /&gt;
* &#039;&#039;&#039;Cases having task&#039;&#039;&#039;: Number of cases in the process mining data, that have this task (=event type).&lt;br /&gt;
* &#039;&#039;&#039;Task occurred&#039;&#039;&#039;: Number of times this type of event has occurred in the process mining data. This number is the same or larger than the Cases having task count. If it&#039;s larger, the event has occurred more than once in a case (looping, repetition).&lt;br /&gt;
&lt;br /&gt;
Flow has a different meaning in the BPMN diagram than in the traditional process mining diagram. In the process mining diagram, a flow is &#039;&#039;direct&#039;&#039; transition between two events. This means that no other event has occurred between the start and end event of the flow. In the BPMN diagram. Following KPI&#039;s for flows are shown for in-memory models (there are no flow KPI&#039;s for Snowflake models):&lt;br /&gt;
* &#039;&#039;&#039;Flow median duration&#039;&#039;&#039;: Median duration from the task event of the flow to the end event of the flow.&lt;br /&gt;
* &#039;&#039;&#039;Flow occurred&#039;&#039;&#039;: Number of times the flow has occurred in all cases. The BPMN flow occurs when in the case there occurs the starting event and that is followed by the end event at any point in the case.&lt;br /&gt;
* &#039;&#039;&#039;Other events between&#039;&#039;&#039;: Number of events that has occurred between the starting and ending event in the flow.&lt;br /&gt;
&lt;br /&gt;
== Design Model Selector ==&lt;br /&gt;
In addition to the &#039;&#039;BPMN Editor&#039;&#039;, there is also a &#039;&#039;&#039;Design Model Selector&#039;&#039;&#039; component available, which adds a button to the dashboard for opening an overlay BPMN editor. The Design Model Selector is better when there is no space in the dashboard to show the BPMN model.&lt;br /&gt;
&lt;br /&gt;
The Design Model Selector validates the BPMN model when the editor is closed, so invalid BPMN models cannot be saved.&lt;br /&gt;
&lt;br /&gt;
== Conformance Statistics ==&lt;br /&gt;
&#039;&#039;&#039;Conformance Statistics&#039;&#039;&#039; visualization shows an overview of how many cases are conformant and deviating (both as absolute case count and percentage of total cases). In addition, the Conformance Statistics component shown average duration of cases and average number of events per case in both the conformant and deviating cases groups. The used BPMN model is stored in the &#039;&#039;designModel&#039;&#039; variable in the context of the conformance statistics visualization.&lt;br /&gt;
&lt;br /&gt;
[[Category: QPR ProcessAnalyzer]]&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_BPMN_Editor&amp;diff=28283</id>
		<title>QPR ProcessAnalyzer BPMN Editor</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_BPMN_Editor&amp;diff=28283"/>
		<updated>2026-05-06T08:17:58Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63956&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page describes components that are used for editing BPMN models and viewing conformance analysis results. Note that for dashboards that use BPMN and conformance functionality, you need to create a variable &#039;&#039;&#039;designModel&#039;&#039;&#039; with behavior &#039;&#039;Stored&#039;&#039; (in the &#039;&#039;Dashboard Properties&#039;&#039; in &#039;&#039;Variables&#039;&#039; tab), so that the dashboard is able to store the defined BPMN model. Note also that the BPMN editor only allows to add BPMN elements that are supported by the conformance checking functionality.&lt;br /&gt;
&lt;br /&gt;
== BPMN Editor ==&lt;br /&gt;
The &#039;&#039;&#039;BPMN Editor&#039;&#039;&#039; analyzes process mining data with the help of a designed BPMN process model. You can for example:&lt;br /&gt;
* See process mining KPI&#039;s and statistics calculated on the fly top of the BPMN diagram during the modeling the BPMN&lt;br /&gt;
* Run conformance analysis using the designed BPMN model&lt;br /&gt;
* Filter data directly from the BPMN diagram&lt;br /&gt;
&lt;br /&gt;
The BPMN diagram can be drawn from scratch, opened from QPR ProcessDesigner repository via QPR MEA Web Service, or imported from a BPMN 2.0 XML file. The ready diagram can be saved to the QPR ProcessDesigner repository or exported to a BPMN 2.0 XML file.&lt;br /&gt;
&lt;br /&gt;
BPMN diagrams are created by dragging items from the tool palette. Start event, end event, task and gateways are the most used elements. When you add a BPMN task to the canvas, all event types are shown in a list next to the task, and an event type can be selected to match it with the created task. When the task is added, KPI values are calculated and shown in the blue background. When flows are added, KPI values are calculated and shown for them, too. By clicking the KPI in the top right legend, the KPI value is hidden, to make the BPMN diagram more readable if there are lots of items.&lt;br /&gt;
&lt;br /&gt;
When you select a BPMN task, it suggest to create a filter. In the dropdown list you can select which type of filter is created. When you select a BPMN flow, it also suggest to create a filter.&lt;br /&gt;
&lt;br /&gt;
You can create a filter to get only the conforming or nonconforming cases based on the current BPMN model by selecting &#039;&#039;&#039;Include conforming cases&#039;&#039;&#039; or &#039;&#039;&#039;Include nonconforming cases&#039;&#039;&#039; from the context menu.&lt;br /&gt;
&lt;br /&gt;
=== Auto-creating BPMN Diagram from Eventlog ===&lt;br /&gt;
BPMN editor&#039;s context menu has the &#039;&#039;&#039;Auto-create diagram&#039;&#039;&#039; option which will automatically create and layout a fully conforming BPMN diagram from the filtered eventlog. The created diagram contains paths for all the process variations in the filtered eventlog. The diagram will have one start element and one end element, all the event types appear as BPMN tasks in the diagram. The auto-creation intelligently identifies the types of gateways, using either the exclusive or parallel gateways. Parallel gateways indicate that there are activities occurring simultaneously in the process that are typically independent of each other.&lt;br /&gt;
&lt;br /&gt;
Eventlogs often contain a large number of process variations, even in smaller datasets. Capturing every variation in a single BPMN diagram can quickly lead to a model that is overly complex and difficult to interpret. A practical approach is to first filter the eventlog to include only the cases that represent the desired variations or process behaviors. Using the variation filter is typically the easiest way to select the process behavior you want to include to the BPMN diagram. You may need to iterate a few times by adjusting filters and regenerating the diagram to arrive at a BPMN model that represents the desired process flow. If the auto-created diagram still does not fully meet your needs, you can always continue refining it manually using the BPMN editor.&lt;br /&gt;
&lt;br /&gt;
The auto-creation feature is available for the Snowflake models, and it uses the expression language&#039;s [[Generic_Functions_in_QPR_ProcessAnalyzer#:~:text=ToBpmn|ToBpmn]] function which generates the BPMN diagram in the Snowflake by calling a Python function powered by the PM4Py library (https://processintelligence.solutions/pm4py). The function is executed in the same Snowflake ODBC connection where the eventlog data is located. To use the auto-creation feature, the required Python libraries need to be deployed to Snowflake as instructed [[Snowflake_Connection_Configuration#Enable_auto-create_BPMN_diagrams|here]].&lt;br /&gt;
&lt;br /&gt;
=== Adding tasks and flows, and Deleting Diagram ===&lt;br /&gt;
There are following functions available:&lt;br /&gt;
* &#039;&#039;&#039;Add tasks and flows&#039;&#039;&#039; will create a BPMN model that is the same as the as-is model. Thus, the as-is model will conform perfectly to the design model. After the tasks and flows are created, you can edit the design model and remove the events and flows that shouldn&#039;t occur in the process. Note however, that the amount of flows that is created can easily be overwhelming. To overcome this, you can first filter out those events and flows that shouldn&#039;t occur in the desired process and then use the auto-create. After creating the design model, you can remove the filter to check the conformance of the whole model. Note that due to performance reasons, the number of flows in the auto-generated model is limited to 1000.&lt;br /&gt;
* &#039;&#039;&#039;Add tasks only&#039;&#039;&#039; will generate only the tasks without any flows. The result is a model that needs to be filled with flows to be a valid BPMN model.&lt;br /&gt;
* &#039;&#039;&#039;Delete diagram&#039;&#039;&#039; will delete the current diagram and start from an empty canvas.&lt;br /&gt;
&lt;br /&gt;
=== Opening and Saving a Diagram in the Repository ===&lt;br /&gt;
To open a diagram from the repository:&lt;br /&gt;
# Click the &#039;&#039;&#039;Open diagram from repository&#039;&#039;&#039; button on the bottom left of the BPMN Editor. The Open Diagram from Repository dialog will open.&lt;br /&gt;
# In the &#039;&#039;&#039;Process Models&#039;&#039;&#039; hierarchy, select a BPMN model.&lt;br /&gt;
# In the &#039;&#039;&#039;Diagrams&#039;&#039;&#039; hierarchy, select a BPMN diagram.&lt;br /&gt;
# Click &#039;&#039;&#039;Open&#039;&#039;&#039;.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To save a diagram to the repository:&lt;br /&gt;
# Click the &#039;&#039;&#039;Save diagram to repository&#039;&#039;&#039; button on the bottom left of the BPMN Editor. The Save Diagram to Repository dialog will open.&lt;br /&gt;
# In the &#039;&#039;&#039;Process Models&#039;&#039;&#039; hierarchy, select a BPMN model.&lt;br /&gt;
# In &#039;&#039;&#039;Diagrams&#039;&#039;&#039; hierarchy, select the target BPMN diagram location.&lt;br /&gt;
# Click &#039;&#039;&#039;Save&#039;&#039;&#039;.&lt;br /&gt;
Note that a BPMN diagram may contain an entire diagram hierarchy. When a BPMN diagram is saved, the entire diagram hierarchy is replaced at the level where the saving is made.&lt;br /&gt;
&lt;br /&gt;
=== Creating a New Diagram to the Repository ===&lt;br /&gt;
A new diagram can be created to the repository as follows:&lt;br /&gt;
# Click the &#039;&#039;&#039;Save diagram to repository&#039;&#039;&#039; button on the bottom left of the BPMN Editor. The Save Diagram to Repository dialog will open.&lt;br /&gt;
# Select the diagram under which the new diagram should be created.&lt;br /&gt;
# Click &#039;&#039;&#039;New Diagram&#039;&#039;&#039;.&lt;br /&gt;
# Enter the diagram name in the dialog that opens. A duplicate name cannot be created on the same diagram level.&lt;br /&gt;
# Click &#039;&#039;&#039;Create&#039;&#039;&#039;.&lt;br /&gt;
After creation, the new diagram is added under the previously selected diagram.&lt;br /&gt;
&lt;br /&gt;
=== Renaming or Deleting a Diagram from the Repository ===&lt;br /&gt;
A diagram can be renamed or deleted from the repository as follows:&lt;br /&gt;
# Click the &#039;&#039;&#039;Save diagram to repository&#039;&#039;&#039; button on the bottom left of the BPMN Editor. The Save Diagram to Repository dialog will open.&lt;br /&gt;
# Select the diagram you want to rename or delete.&lt;br /&gt;
# Click either &#039;&#039;&#039;Rename Diagram&#039;&#039;&#039; or &#039;&#039;&#039;Delete Diagram&#039;&#039;&#039;.&lt;br /&gt;
# Depending on the chosen action, give a new name for the diagram and click &#039;&#039;&#039;Rename&#039;&#039;&#039; or click &#039;&#039;&#039;Delete&#039;&#039;&#039; in the confirmation dialog.&lt;br /&gt;
&lt;br /&gt;
=== Reports Selectable in BPMN Diagram ===&lt;br /&gt;
There are also following reports available for in-memory models:&lt;br /&gt;
* &#039;&#039;&#039;Duration distribution between tasks&#039;&#039;&#039; (select 2 tasks)&lt;br /&gt;
* &#039;&#039;&#039;Flow duration distribution&#039;&#039;&#039; (select 1 flow)&lt;br /&gt;
* &#039;&#039;&#039;Task occurrences across time&#039;&#039;&#039; (select 1 task)&lt;br /&gt;
* &#039;&#039;&#039;Task repetition in cases&#039;&#039;&#039; (select 1 task)&lt;br /&gt;
* You can export the BPMN diagram contents as a flat list by clicking the &#039;&#039;&#039;Export all BPMN elements as CSV&#039;&#039;&#039;.&lt;br /&gt;
* You can export a list of BPMN elements in the order that they appear in the flow by clicking the &#039;&#039;&#039;Export element order&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== KPI&#039;s on BPMN Diagram===&lt;br /&gt;
The following KPI&#039;s are shown:&lt;br /&gt;
* &#039;&#039;&#039;Cases having task&#039;&#039;&#039;: Number of cases in the process mining data, that have this task (=event type).&lt;br /&gt;
* &#039;&#039;&#039;Task occurred&#039;&#039;&#039;: Number of times this type of event has occurred in the process mining data. This number is the same or larger than the Cases having task count. If it&#039;s larger, the event has occurred more than once in a case (looping, repetition).&lt;br /&gt;
&lt;br /&gt;
Flow has a different meaning in the BPMN diagram than in the traditional process mining diagram. In the process mining diagram, a flow is &#039;&#039;direct&#039;&#039; transition between two events. This means that no other event has occurred between the start and end event of the flow. In the BPMN diagram. Following KPI&#039;s for flows are shown for in-memory models (there are no flow KPI&#039;s for Snowflake models):&lt;br /&gt;
* &#039;&#039;&#039;Flow median duration&#039;&#039;&#039;: Median duration from the task event of the flow to the end event of the flow.&lt;br /&gt;
* &#039;&#039;&#039;Flow occurred&#039;&#039;&#039;: Number of times the flow has occurred in all cases. The BPMN flow occurs when in the case there occurs the starting event and that is followed by the end event at any point in the case.&lt;br /&gt;
* &#039;&#039;&#039;Other events between&#039;&#039;&#039;: Number of events that has occurred between the starting and ending event in the flow.&lt;br /&gt;
&lt;br /&gt;
== Design Model Selector ==&lt;br /&gt;
In addition to the &#039;&#039;BPMN Editor&#039;&#039;, there is also a &#039;&#039;&#039;Design Model Selector&#039;&#039;&#039; component available, which adds a button to the dashboard for opening an overlay BPMN editor. The Design Model Selector is better when there is no space in the dashboard to show the BPMN model.&lt;br /&gt;
&lt;br /&gt;
The Design Model Selector validates the BPMN model when the editor is closed, so invalid BPMN models cannot be saved.&lt;br /&gt;
&lt;br /&gt;
== Conformance Statistics ==&lt;br /&gt;
&#039;&#039;&#039;Conformance Statistics&#039;&#039;&#039; visualization shows an overview of how many cases are conformant and deviating (both as absolute case count and percentage of total cases). In addition, the Conformance Statistics component shown average duration of cases and average number of events per case in both the conformant and deviating cases groups. The used BPMN model is stored in the &#039;&#039;designModel&#039;&#039; variable in the context of the conformance statistics visualization.&lt;br /&gt;
&lt;br /&gt;
[[Category: QPR ProcessAnalyzer]]&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_BPMN_Editor&amp;diff=28282</id>
		<title>QPR ProcessAnalyzer BPMN Editor</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_BPMN_Editor&amp;diff=28282"/>
		<updated>2026-05-06T08:12:48Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63956&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page describes components that are used for editing BPMN models and viewing conformance analysis results. Note that for dashboards that use BPMN and conformance functionality, you need to create a variable &#039;&#039;&#039;designModel&#039;&#039;&#039; with behavior &#039;&#039;Stored&#039;&#039; (in the &#039;&#039;Dashboard Properties&#039;&#039; in &#039;&#039;Variables&#039;&#039; tab), so that the dashboard is able to store the defined BPMN model. Note also that the BPMN editor only allows to add BPMN elements that are supported by the conformance checking functionality.&lt;br /&gt;
&lt;br /&gt;
== BPMN Editor ==&lt;br /&gt;
The &#039;&#039;&#039;BPMN Editor&#039;&#039;&#039; analyzes process mining data with the help of a designed BPMN process model. You can for example:&lt;br /&gt;
* See process mining KPI&#039;s and statistics calculated on the fly top of the BPMN diagram during the modeling the BPMN&lt;br /&gt;
* Run conformance analysis using the designed BPMN model&lt;br /&gt;
* Filter data directly from the BPMN diagram&lt;br /&gt;
&lt;br /&gt;
The BPMN diagram can be drawn from scratch, opened from QPR ProcessDesigner repository via QPR MEA Web Service, or imported from a BPMN 2.0 XML file. The ready diagram can be saved to the QPR ProcessDesigner repository or exported to a BPMN 2.0 XML file.&lt;br /&gt;
&lt;br /&gt;
BPMN diagrams are created by dragging items from the tool palette. Start event, end event, task and gateways are the most used elements. When you add a BPMN task to the canvas, all event types are shown in a list next to the task, and an event type can be selected to match it with the created task. When the task is added, KPI values are calculated and shown in the blue background. When flows are added, KPI values are calculated and shown for them, too. By clicking the KPI in the top right legend, the KPI value is hidden, to make the BPMN diagram more readable if there are lots of items.&lt;br /&gt;
&lt;br /&gt;
When you select a BPMN task, it suggest to create a filter. In the dropdown list you can select which type of filter is created. When you select a BPMN flow, it also suggest to create a filter.&lt;br /&gt;
&lt;br /&gt;
You can create a filter to get only the conforming or nonconforming cases based on the current BPMN model by selecting &#039;&#039;&#039;Include conforming cases&#039;&#039;&#039; or &#039;&#039;&#039;Include nonconforming cases&#039;&#039;&#039; from the context menu.&lt;br /&gt;
&lt;br /&gt;
=== Auto-creating BPMN Diagram from Eventlog ===&lt;br /&gt;
BPMN editor&#039;s context menu has the &#039;&#039;&#039;Auto-create diagram&#039;&#039;&#039; option which will automatically create and layout a fully conforming BPMN diagram from the filtered eventlog. The created diagram contains paths for all the process variations in the filtered eventlog. The diagram will have one start element and one end element, all the event types appear as BPMN tasks in the diagram. The auto-creation intelligently identifies the types of gateways, using either the exclusive or parallel gateways. Parallel gateways indicate that there are activities occurring simultaneously in the process that are typically independent of each other.&lt;br /&gt;
&lt;br /&gt;
Eventlogs often contain a large number of process variations, even in smaller datasets. Capturing every variation in a single BPMN diagram can quickly lead to a model that is overly complex and difficult to interpret. A practical approach is to first filter the eventlog to include only the cases that represent the desired variations or process behaviors. Using the variation filter is typically the easiest way to select the process behavior you want to include to the BPMN diagram. You may need to iterate a few times by adjusting filters and regenerating the diagram to arrive at a BPMN model that represents the desired process flow. If the auto-created diagram still does not fully meet your needs, you can always continue refining it manually using the BPMN editor.&lt;br /&gt;
&lt;br /&gt;
The auto-creation feature is available for the Snowflake models, and it uses the expression language&#039;s [[Generic_Functions_in_QPR_ProcessAnalyzer#:~:text=ToBpmn|ToBpmn]] function which generates the BPMN diagram in the Snowflake by calling a Python function powered by the PM4Py library (https://processintelligence.solutions/pm4py). The function is executed in the same Snowflake ODBC connection where the eventlog data is located. To use the auto-creation feature, the required Python libraries need to be deployed to Snowflake as instructed [[Snowflake_Connection_Configuration#Enable_auto-create_BPMN_diagrams|here]].&lt;br /&gt;
&lt;br /&gt;
=== Adding tasks and flows, and Deleting Diagram ===&lt;br /&gt;
There are following functions available:&lt;br /&gt;
* &#039;&#039;&#039;Add tasks and flows&#039;&#039;&#039; will create a BPMN model that is the same as the as-is model. Thus, the as-is model will conform perfectly to the design model. After the tasks and flows are created, you can edit the design model and remove the events and flows that shouldn&#039;t occur in the process. Note however, that the amount of flows that is created can easily be overwhelming. To overcome this, you can first filter out those events and flows that shouldn&#039;t occur in the desired process and then use the auto-create. After creating the design model, you can remove the filter to check the conformance of the whole model. Note that due to performance reasons, the number of flows in the auto-generated model is limited to 1000.&lt;br /&gt;
* &#039;&#039;&#039;Add tasks only&#039;&#039;&#039; will generate only the tasks without any flows. The result is a model that needs to be filled with flows to be a valid BPMN model.&lt;br /&gt;
* &#039;&#039;&#039;Delete diagram&#039;&#039;&#039; will delete the current diagram and start from an empty canvas.&lt;br /&gt;
&lt;br /&gt;
=== Opening and Saving a Diagram in the Repository ===&lt;br /&gt;
To open a diagram from the repository:&lt;br /&gt;
# Click the &#039;&#039;&#039;Open diagram from repository&#039;&#039;&#039; button on the bottom left of the BPMN Editor. The Open Diagram from Repository dialog will open.&lt;br /&gt;
# In the &#039;&#039;&#039;Process Models&#039;&#039;&#039; hierarchy, select a BPMN model.&lt;br /&gt;
# In the &#039;&#039;&#039;Diagrams&#039;&#039;&#039; hierarchy, select a BPMN diagram.&lt;br /&gt;
# Click &#039;&#039;&#039;Open&#039;&#039;&#039;.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To save a diagram to the repository:&lt;br /&gt;
# Click the &#039;&#039;&#039;Save diagram to repository&#039;&#039;&#039; button on the bottom left of the BPMN Editor. The Save Diagram to Repository dialog will open.&lt;br /&gt;
# In the &#039;&#039;&#039;Process Models&#039;&#039;&#039; hierarchy, select a BPMN model.&lt;br /&gt;
# In &#039;&#039;&#039;Diagrams&#039;&#039;&#039; hierarchy, select the target BPMN diagram location.&lt;br /&gt;
# Click &#039;&#039;&#039;Save&#039;&#039;&#039;.&lt;br /&gt;
Note that a BPMN diagram may contain an entire diagram hierarchy. When a BPMN diagram is saved, the entire diagram hierarchy is replaced at the level where the saving is made.&lt;br /&gt;
&lt;br /&gt;
=== Creating a New Diagram to the Repository ===&lt;br /&gt;
A new diagram can be created to the repository as follows:&lt;br /&gt;
# Click the &#039;&#039;&#039;Save diagram to repository&#039;&#039;&#039; button on the bottom left of the BPMN Editor. The Save Diagram to Repository dialog will open.&lt;br /&gt;
# Select the diagram under which the new diagram should be created.&lt;br /&gt;
# Click &#039;&#039;&#039;New Diagram&#039;&#039;&#039;.&lt;br /&gt;
# Enter the diagram name in the dialog that opens. A duplicate name cannot be created on the same diagram level.&lt;br /&gt;
# Click &#039;&#039;&#039;Create&#039;&#039;&#039;.&lt;br /&gt;
After creation, the new diagram is added under the previously selected diagram.&lt;br /&gt;
&lt;br /&gt;
=== Reports Selectable in BPMN Diagram ===&lt;br /&gt;
There are also following reports available for in-memory models:&lt;br /&gt;
* &#039;&#039;&#039;Duration distribution between tasks&#039;&#039;&#039; (select 2 tasks)&lt;br /&gt;
* &#039;&#039;&#039;Flow duration distribution&#039;&#039;&#039; (select 1 flow)&lt;br /&gt;
* &#039;&#039;&#039;Task occurrences across time&#039;&#039;&#039; (select 1 task)&lt;br /&gt;
* &#039;&#039;&#039;Task repetition in cases&#039;&#039;&#039; (select 1 task)&lt;br /&gt;
* You can export the BPMN diagram contents as a flat list by clicking the &#039;&#039;&#039;Export all BPMN elements as CSV&#039;&#039;&#039;.&lt;br /&gt;
* You can export a list of BPMN elements in the order that they appear in the flow by clicking the &#039;&#039;&#039;Export element order&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== KPI&#039;s on BPMN Diagram===&lt;br /&gt;
The following KPI&#039;s are shown:&lt;br /&gt;
* &#039;&#039;&#039;Cases having task&#039;&#039;&#039;: Number of cases in the process mining data, that have this task (=event type).&lt;br /&gt;
* &#039;&#039;&#039;Task occurred&#039;&#039;&#039;: Number of times this type of event has occurred in the process mining data. This number is the same or larger than the Cases having task count. If it&#039;s larger, the event has occurred more than once in a case (looping, repetition).&lt;br /&gt;
&lt;br /&gt;
Flow has a different meaning in the BPMN diagram than in the traditional process mining diagram. In the process mining diagram, a flow is &#039;&#039;direct&#039;&#039; transition between two events. This means that no other event has occurred between the start and end event of the flow. In the BPMN diagram. Following KPI&#039;s for flows are shown for in-memory models (there are no flow KPI&#039;s for Snowflake models):&lt;br /&gt;
* &#039;&#039;&#039;Flow median duration&#039;&#039;&#039;: Median duration from the task event of the flow to the end event of the flow.&lt;br /&gt;
* &#039;&#039;&#039;Flow occurred&#039;&#039;&#039;: Number of times the flow has occurred in all cases. The BPMN flow occurs when in the case there occurs the starting event and that is followed by the end event at any point in the case.&lt;br /&gt;
* &#039;&#039;&#039;Other events between&#039;&#039;&#039;: Number of events that has occurred between the starting and ending event in the flow.&lt;br /&gt;
&lt;br /&gt;
== Design Model Selector ==&lt;br /&gt;
In addition to the &#039;&#039;BPMN Editor&#039;&#039;, there is also a &#039;&#039;&#039;Design Model Selector&#039;&#039;&#039; component available, which adds a button to the dashboard for opening an overlay BPMN editor. The Design Model Selector is better when there is no space in the dashboard to show the BPMN model.&lt;br /&gt;
&lt;br /&gt;
The Design Model Selector validates the BPMN model when the editor is closed, so invalid BPMN models cannot be saved.&lt;br /&gt;
&lt;br /&gt;
== Conformance Statistics ==&lt;br /&gt;
&#039;&#039;&#039;Conformance Statistics&#039;&#039;&#039; visualization shows an overview of how many cases are conformant and deviating (both as absolute case count and percentage of total cases). In addition, the Conformance Statistics component shown average duration of cases and average number of events per case in both the conformant and deviating cases groups. The used BPMN model is stored in the &#039;&#039;designModel&#039;&#039; variable in the context of the conformance statistics visualization.&lt;br /&gt;
&lt;br /&gt;
[[Category: QPR ProcessAnalyzer]]&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_BPMN_Editor&amp;diff=28281</id>
		<title>QPR ProcessAnalyzer BPMN Editor</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_BPMN_Editor&amp;diff=28281"/>
		<updated>2026-05-06T07:13:29Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63956&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page describes components that are used for editing BPMN models and viewing conformance analysis results. Note that for dashboards that use BPMN and conformance functionality, you need to create a variable &#039;&#039;&#039;designModel&#039;&#039;&#039; with behavior &#039;&#039;Stored&#039;&#039; (in the &#039;&#039;Dashboard Properties&#039;&#039; in &#039;&#039;Variables&#039;&#039; tab), so that the dashboard is able to store the defined BPMN model. Note also that the BPMN editor only allows to add BPMN elements that are supported by the conformance checking functionality.&lt;br /&gt;
&lt;br /&gt;
== BPMN Editor ==&lt;br /&gt;
The &#039;&#039;&#039;BPMN Editor&#039;&#039;&#039; analyzes process mining data with the help of a designed BPMN process model. You can for example:&lt;br /&gt;
* See process mining KPI&#039;s and statistics calculated on the fly top of the BPMN diagram during the modeling the BPMN&lt;br /&gt;
* Run conformance analysis using the designed BPMN model&lt;br /&gt;
* Filter data directly from the BPMN diagram&lt;br /&gt;
&lt;br /&gt;
The BPMN diagram can be drawn from scratch, opened from QPR ProcessDesigner repository via QPR MEA Web Service, or imported from a BPMN 2.0 XML file. The ready diagram can be saved to the QPR ProcessDesigner repository or exported to a BPMN 2.0 XML file.&lt;br /&gt;
&lt;br /&gt;
BPMN diagrams are created by dragging items from the tool palette. Start event, end event, task and gateways are the most used elements. When you add a BPMN task to the canvas, all event types are shown in a list next to the task, and an event type can be selected to match it with the created task. When the task is added, KPI values are calculated and shown in the blue background. When flows are added, KPI values are calculated and shown for them, too. By clicking the KPI in the top right legend, the KPI value is hidden, to make the BPMN diagram more readable if there are lots of items.&lt;br /&gt;
&lt;br /&gt;
When you select a BPMN task, it suggest to create a filter. In the dropdown list you can select which type of filter is created. When you select a BPMN flow, it also suggest to create a filter.&lt;br /&gt;
&lt;br /&gt;
You can create a filter to get only the conforming or nonconforming cases based on the current BPMN model by selecting &#039;&#039;&#039;Include conforming cases&#039;&#039;&#039; or &#039;&#039;&#039;Include nonconforming cases&#039;&#039;&#039; from the context menu.&lt;br /&gt;
&lt;br /&gt;
=== Auto-creating BPMN Diagram from Eventlog ===&lt;br /&gt;
BPMN editor&#039;s context menu has the &#039;&#039;&#039;Auto-create diagram&#039;&#039;&#039; option which will automatically create and layout a fully conforming BPMN diagram from the filtered eventlog. The created diagram contains paths for all the process variations in the filtered eventlog. The diagram will have one start element and one end element, all the event types appear as BPMN tasks in the diagram. The auto-creation intelligently identifies the types of gateways, using either the exclusive or parallel gateways. Parallel gateways indicate that there are activities occurring simultaneously in the process that are typically independent of each other.&lt;br /&gt;
&lt;br /&gt;
Eventlogs often contain a large number of process variations, even in smaller datasets. Capturing every variation in a single BPMN diagram can quickly lead to a model that is overly complex and difficult to interpret. A practical approach is to first filter the eventlog to include only the cases that represent the desired variations or process behaviors. Using the variation filter is typically the easiest way to select the process behavior you want to include to the BPMN diagram. You may need to iterate a few times by adjusting filters and regenerating the diagram to arrive at a BPMN model that represents the desired process flow. If the auto-created diagram still does not fully meet your needs, you can always continue refining it manually using the BPMN editor.&lt;br /&gt;
&lt;br /&gt;
The auto-creation feature is available for the Snowflake models, and it uses the expression language&#039;s [[Generic_Functions_in_QPR_ProcessAnalyzer#:~:text=ToBpmn|ToBpmn]] function which generates the BPMN diagram in the Snowflake by calling a Python function powered by the PM4Py library (https://processintelligence.solutions/pm4py). The function is executed in the same Snowflake ODBC connection where the eventlog data is located. To use the auto-creation feature, the required Python libraries need to be deployed to Snowflake as instructed [[Snowflake_Connection_Configuration#Enable_auto-create_BPMN_diagrams|here]].&lt;br /&gt;
&lt;br /&gt;
=== Adding tasks and flows, and Deleting Diagram ===&lt;br /&gt;
There are following functions available:&lt;br /&gt;
* &#039;&#039;&#039;Add tasks and flows&#039;&#039;&#039; will create a BPMN model that is the same as the as-is model. Thus, the as-is model will conform perfectly to the design model. After the tasks and flows are created, you can edit the design model and remove the events and flows that shouldn&#039;t occur in the process. Note however, that the amount of flows that is created can easily be overwhelming. To overcome this, you can first filter out those events and flows that shouldn&#039;t occur in the desired process and then use the auto-create. After creating the design model, you can remove the filter to check the conformance of the whole model. Note that due to performance reasons, the number of flows in the auto-generated model is limited to 1000.&lt;br /&gt;
* &#039;&#039;&#039;Add tasks only&#039;&#039;&#039; will generate only the tasks without any flows. The result is a model that needs to be filled with flows to be a valid BPMN model.&lt;br /&gt;
* &#039;&#039;&#039;Delete diagram&#039;&#039;&#039; will delete the current diagram and start from an empty canvas.&lt;br /&gt;
&lt;br /&gt;
=== Reports Selectable in BPMN Diagram ===&lt;br /&gt;
There are also following reports available for in-memory models:&lt;br /&gt;
* &#039;&#039;&#039;Duration distribution between tasks&#039;&#039;&#039; (select 2 tasks)&lt;br /&gt;
* &#039;&#039;&#039;Flow duration distribution&#039;&#039;&#039; (select 1 flow)&lt;br /&gt;
* &#039;&#039;&#039;Task occurrences across time&#039;&#039;&#039; (select 1 task)&lt;br /&gt;
* &#039;&#039;&#039;Task repetition in cases&#039;&#039;&#039; (select 1 task)&lt;br /&gt;
* You can export the BPMN diagram contents as a flat list by clicking the &#039;&#039;&#039;Export all BPMN elements as CSV&#039;&#039;&#039;.&lt;br /&gt;
* You can export a list of BPMN elements in the order that they appear in the flow by clicking the &#039;&#039;&#039;Export element order&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== KPI&#039;s on BPMN Diagram===&lt;br /&gt;
The following KPI&#039;s are shown:&lt;br /&gt;
* &#039;&#039;&#039;Cases having task&#039;&#039;&#039;: Number of cases in the process mining data, that have this task (=event type).&lt;br /&gt;
* &#039;&#039;&#039;Task occurred&#039;&#039;&#039;: Number of times this type of event has occurred in the process mining data. This number is the same or larger than the Cases having task count. If it&#039;s larger, the event has occurred more than once in a case (looping, repetition).&lt;br /&gt;
&lt;br /&gt;
Flow has a different meaning in the BPMN diagram than in the traditional process mining diagram. In the process mining diagram, a flow is &#039;&#039;direct&#039;&#039; transition between two events. This means that no other event has occurred between the start and end event of the flow. In the BPMN diagram. Following KPI&#039;s for flows are shown for in-memory models (there are no flow KPI&#039;s for Snowflake models):&lt;br /&gt;
* &#039;&#039;&#039;Flow median duration&#039;&#039;&#039;: Median duration from the task event of the flow to the end event of the flow.&lt;br /&gt;
* &#039;&#039;&#039;Flow occurred&#039;&#039;&#039;: Number of times the flow has occurred in all cases. The BPMN flow occurs when in the case there occurs the starting event and that is followed by the end event at any point in the case.&lt;br /&gt;
* &#039;&#039;&#039;Other events between&#039;&#039;&#039;: Number of events that has occurred between the starting and ending event in the flow.&lt;br /&gt;
&lt;br /&gt;
== Design Model Selector ==&lt;br /&gt;
In addition to the &#039;&#039;BPMN Editor&#039;&#039;, there is also a &#039;&#039;&#039;Design Model Selector&#039;&#039;&#039; component available, which adds a button to the dashboard for opening an overlay BPMN editor. The Design Model Selector is better when there is no space in the dashboard to show the BPMN model.&lt;br /&gt;
&lt;br /&gt;
The Design Model Selector validates the BPMN model when the editor is closed, so invalid BPMN models cannot be saved.&lt;br /&gt;
&lt;br /&gt;
== Conformance Statistics ==&lt;br /&gt;
&#039;&#039;&#039;Conformance Statistics&#039;&#039;&#039; visualization shows an overview of how many cases are conformant and deviating (both as absolute case count and percentage of total cases). In addition, the Conformance Statistics component shown average duration of cases and average number of events per case in both the conformant and deviating cases groups. The used BPMN model is stored in the &#039;&#039;designModel&#039;&#039; variable in the context of the conformance statistics visualization.&lt;br /&gt;
&lt;br /&gt;
[[Category: QPR ProcessAnalyzer]]&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=PA_Configuration_database_table&amp;diff=28221</id>
		<title>PA Configuration database table</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=PA_Configuration_database_table&amp;diff=28221"/>
		<updated>2026-04-28T12:05:17Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-64494&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer database has a configuration table &#039;&#039;&#039;PA_Configuration&#039;&#039;&#039; containing settings listed in the tables below. You need &#039;&#039;&#039;SQL Server Management Studio&#039;&#039;&#039; to edit the settings in the configuration table. QPR ProcessAnalyzer Server needs to be restarted (e.g. IIS application pool recycled) for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
For boolean values, &#039;&#039;true&#039;&#039; and &#039;&#039;1&#039;&#039; are valid values for yes, and &#039;&#039;false&#039;&#039; and &#039;&#039;0&#039;&#039; are valid for no.&lt;br /&gt;
&lt;br /&gt;
== General Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||DefaultDataSource&lt;br /&gt;
||&lt;br /&gt;
||Datasource where datatables data is stored when datatables are created by a script when the datasource is not explicitly specified in the script. Options are &#039;&#039;&#039;Snowflake&#039;&#039;&#039; and &#039;&#039;&#039;SqlServer&#039;&#039;&#039;. Value &#039;&#039;snowflake&#039;&#039; can be used when the &#039;&#039;SnowflakeConnectionString&#039;&#039; setting is defined, and value &#039;&#039;sqlserver&#039;&#039; can be used when the setting &#039;&#039;SqlServerConnectionString&#039;&#039; is configured. The setting can be changed without affecting the existing datatables, as the setting only affect new datatables. When this setting is empty, datatables are created in the metadata database.&lt;br /&gt;
|-&lt;br /&gt;
||SnowflakeConnectionString&lt;br /&gt;
||&lt;br /&gt;
||ODBC connection string for the Snowflake account. This setting is needed to make analytics calculations in the Snowflake. More information how to configure the [[Snowflake_Connection_Configuration#Set_Snowflake_ODBC_connection|Snowflake connection string]]. The Snowflake ODBC driver also needs to be installed in the machine running the QPR ProcessAnalyzer Server. When this setting has been configured, users can create Snowflake stored datatables and models using Snowflake calculation.&lt;br /&gt;
&lt;br /&gt;
When running QPR ProcessAnalyzer in the Snowpark Container Services, leave the SnowflakeConnectionString empty because then the connection string is created automatically using the method provided by the Snowpark Container Services.&lt;br /&gt;
|-&lt;br /&gt;
||SqlServerConnectionString&lt;br /&gt;
||&lt;br /&gt;
||Connection string for the SQL Server database containing the datatables data. It&#039;s recommended to use a separate database, but it&#039;s also possible to connect to the same database as the configuration data. If this setting is not configured, local datatables cannot be created (SQL Server stored). Existing datatables located in the configuration datatabase still work even if this setting has not be configured. Note that the connection uses ADO.Net (not ODBC), so the connection string is similar to the configuration database ([[Server_settings_in_appsettings.json|appsettings.json]] file).&lt;br /&gt;
|-&lt;br /&gt;
||DefaultColorPalette&lt;br /&gt;
||&lt;br /&gt;
||Charts color palette used globally in the environment. Defined as a json array of strings encoded with RGB hex (with or without alpha). Note that when a color palette in a chart has been changed, the chart starts using a chart-specific color palette, and the global color palette doesn&#039;t affect those charts. &lt;br /&gt;
&lt;br /&gt;
Example: [&amp;quot;#1F77B4&amp;quot;, &amp;quot;#FF7F0E&amp;quot;, &amp;quot;#2CA02C&amp;quot;, &amp;quot;#D62728&amp;quot;, &amp;quot;#9467BD&amp;quot;, &amp;quot;#8C564B&amp;quot;, &amp;quot;#E377C2&amp;quot;, &amp;quot;#7F7F7F&amp;quot;, &amp;quot;#BCBD22&amp;quot;, &amp;quot;#17BECF&amp;quot;]&lt;br /&gt;
|-&lt;br /&gt;
||OpenAIAPIKey&lt;br /&gt;
||&lt;br /&gt;
||API key for the OpenAI API (https://platform.openai.com/docs/api-reference). It needs to be configured to use the [[AI_Assistant_for_QPR_ProcessAnalyzer|AI Assistant]] and [[Generic_Functions_in_QPR_ProcessAnalyzer#OpenAIChatCompletion|OpenAIChatCompletion]] function.&lt;br /&gt;
|-&lt;br /&gt;
||OpenAIDefaultModelName&lt;br /&gt;
||gpt-4o&lt;br /&gt;
||OpenAI large language model (LLM) to use for the [[AI_Assistant_for_QPR_ProcessAnalyzer|AI Assistant]] and [[Generic_Functions_in_QPR_ProcessAnalyzer#OpenAIChatCompletion|OpenAIChatCompletion]] function. If not defined, &#039;&#039;&#039;gpt-4o&#039;&#039;&#039; will be used. Note that only LLM&#039;s that support the function calling feature, are suitable for the AI Assistant. More information about OpenAI models: https://platform.openai.com/docs/models.&lt;br /&gt;
|-&lt;br /&gt;
||DefaultCortexAgentsModelName&lt;br /&gt;
||llama3.1-70b&lt;br /&gt;
||Specifies the default language model when using Snowflake Cortex Agents (https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-agents-rest-api). If not defined, &#039;&#039;&#039;llama3.1-70b&#039;&#039;&#039; is used.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;QueryTimeout&amp;quot;&amp;gt;QueryTimeout&amp;lt;/span&amp;gt;&lt;br /&gt;
||300&lt;br /&gt;
||Timeout (in seconds) for requests made to /api/expression/query and /api/expression endpoints. When the timeout is exceeded, the query is stopped and a timeout error is returned. Purpose of the timeout is to protect the system against potentially too long running or even never-ending queries which might otherwise jam the system.&lt;br /&gt;
|-&lt;br /&gt;
||SessionIdleTimeout&lt;br /&gt;
||3600&lt;br /&gt;
||Idle user session expiration timeout in seconds. User session expires if the session hasn&#039;t been used after this amount of time.&lt;br /&gt;
|-&lt;br /&gt;
||SessionMaximumDuration&lt;br /&gt;
||86400&lt;br /&gt;
||Maximum duration for a user session in seconds. Even if a session is used so that the SessionIdleTimeout is not reached, the session is expired after this amount of time.&lt;br /&gt;
|-&lt;br /&gt;
|DatabaseId&lt;br /&gt;
|&lt;br /&gt;
||Unique identifier for the QPR ProcessAnalyzer environment. Any characters between a-z, A-Z, 0-9 and _ (underscore) can be used in the DatabaseId. If the DatabaseId is missing or set to null, the system will generate a new GUID during startup and use it as the DatabaseId. The DatabaseId can also be an empty string. If using several QPR ProcessAnalyzer environments, make sure each use a different DatabaseId. The DatabaseId is used as part of the table names in Snowflake and SQL Server (in the datatables database). Thus if the DatabaseId is changed, all tables in Snowflake and SQL Server named with qprpa_dt_&amp;lt;DatabaseId&amp;gt;_&amp;lt;DatatableId&amp;gt; need to be renamed.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;CacheOnlyPrimaryKeysForFilters&amp;quot;&amp;gt;CacheOnlyPrimaryKeysForFilters&amp;lt;/span&amp;gt;&lt;br /&gt;
||false&lt;br /&gt;
||Defines whether to include all columns in the Snowflake event cache filter tables (&#039;&#039;false&#039;&#039;), or only the primary key columns (&#039;&#039;true&#039;&#039;). When &#039;&#039;false&#039;&#039;, cache table creation is slower, but the analysis calculation is faster because the original event table is not used anymore. When &#039;&#039;false&#039;&#039;, also the cache tables require more storage space in Snowflake.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Localization Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||DefaultUiLanguage&lt;br /&gt;
||en_US&lt;br /&gt;
||Language code for the UI language that new user accounts get by default. Thus, a created user account has this language until the user changes her/his language. Also the login page is translated using this language when QPR ProcessAnalyzer is used for the first time in that web browser (when user has changed the language, it&#039;s remembered by the browser). This setting must be one of the supported language codes (xx_XX):&lt;br /&gt;
* English: &#039;&#039;&#039;en_US&#039;&#039;&#039;&lt;br /&gt;
* Finnish: &#039;&#039;&#039;fi_FI&#039;&#039;&#039;&lt;br /&gt;
* French: &#039;&#039;&#039;fr_FR&#039;&#039;&#039;&lt;br /&gt;
* German: &#039;&#039;&#039;de_DE&#039;&#039;&#039;&lt;br /&gt;
* Polish: &#039;&#039;&#039;pl_PL&#039;&#039;&#039;&lt;br /&gt;
* Portuguese: &#039;&#039;&#039;pt_BR&#039;&#039;&#039;&lt;br /&gt;
* Spanish: &#039;&#039;&#039;es_ES&#039;&#039;&#039;&lt;br /&gt;
* Swedish: &#039;&#039;&#039;sv_SE&#039;&#039;&#039;&lt;br /&gt;
* Ukrainian: &#039;&#039;&#039;uk_UK&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||DefaultDateFormat&lt;br /&gt;
||MM/dd/yyyy&lt;br /&gt;
||Default date format that new user accounts get by default. The date format does not contain the time part (e.g. hours, minutes and seconds). Defined using the .Net date format (https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings).&lt;br /&gt;
|-&lt;br /&gt;
||DefaultFirstDayOfWeek&lt;br /&gt;
||0&lt;br /&gt;
||Default first day of the week that new user accounts get by default. &#039;&#039;&#039;0&#039;&#039;&#039; is Sunday and &#039;&#039;&#039;1&#039;&#039;&#039; is Monday. This information is used by the UI when showing e.g. calendars.&lt;br /&gt;
|-&lt;br /&gt;
||DefaultUse12HourClock&lt;br /&gt;
||false&lt;br /&gt;
||Defines whether the 12-hour clock is used by default (instead of the 24-hour clock) for the new user accounts when showing time information in the UI. Defined as &#039;&#039;&#039;true&#039;&#039;&#039; or &#039;&#039;&#039;false&#039;&#039;&#039;. More information about the 12-hour clock: https://en.wikipedia.org/wiki/12-hour_clock.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== ETL Scripts Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||AllowExternalDatasources&lt;br /&gt;
||true&lt;br /&gt;
||Can be used to disallow all connections to external datasources in the expression language and SQL scripts to improve security. Disallowed operations include ODBC, OLE DB, SQL Server (Ado.Net), SAP, Salesforce, and call web service. Note that this setting does not prevent the Snowflake processing. Regardless of this setting, QPR ScriptLauncher can be used to extract data from source systems.&lt;br /&gt;
|-&lt;br /&gt;
||SandboxDatabaseConnectionString&lt;br /&gt;
||&lt;br /&gt;
||Connection string to scripting sandbox database (ETL). If not defined, SQL-based ETL scripts cannot be run. Connection string for the scripting sandbox database is similar to the  [[Server_settings_in_appsettings.json|QPR ProcessAnalyzer database connection string]]. More information: [[Setting up Scripting Sandbox]].&lt;br /&gt;
|-&lt;br /&gt;
||AllowNonTemporaryETLTargetTable&lt;br /&gt;
||false&lt;br /&gt;
||Defined whether ETL scripts are allowed to create global temporary database tables (tables starting with ##). More information about temporary tables: https://docs.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql?view=sql-server-ver15#temporary-tables.&lt;br /&gt;
|-&lt;br /&gt;
||DatabaseBulkCopyTimeout&lt;br /&gt;
||600&lt;br /&gt;
||Timeout used for data import operations to datatables.&lt;br /&gt;
|-&lt;br /&gt;
|SandboxDatabaseBulkCopyTimeout&lt;br /&gt;
||600&lt;br /&gt;
||Timeout used for data import operations to sandbox tables in the SQL scripts.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;DatabaseBulkCopyBatchSize&amp;lt;/span&amp;gt;&lt;br /&gt;
||5000&lt;br /&gt;
||BulkCopyBatchSize given for QPR ProcessAnalyzer database SqlBulkCopy operations.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;SandboxDatabaseBulkCopyBatchSize&amp;lt;/span&amp;gt;&lt;br /&gt;
||5000&lt;br /&gt;
||BulkCopyBatchSize given for sandbox SqlBulkCopy operations.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MCP and OAuth Server Settings ==&lt;br /&gt;
MCP server settings are needed for QPR ProcessAnalyzer to act as an [[QPR_ProcessAnalyzer_as_MCP_Server|MCP server]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||McpServerConfiguration&lt;br /&gt;
||Used to configure the MCP server built-in to ProcessAnalyzer server. If not set, MCP server functionality is disabled and MCP clients can&#039;t access to this server using MCP. If set, contains a string representation of a JSON object that supports the following properties:&lt;br /&gt;
* &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; (string): If defined and not empty, defines the API key that can be used to connect to QPR ProcessAnalyzer MCP server without any other authentication. Default value is empty.&amp;lt;br&amp;gt;&lt;br /&gt;
Example value when using API Key authentication:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{ &amp;quot;McpApiKey&amp;quot;: &amp;quot;xnTqr@Hd87JcuCmQZbjUHfwD@&amp;quot; }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Example value when using OAuth 2.0 authentication:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{ &amp;quot;McpApiKey&amp;quot;: null }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that when using OAuth 2.0 authentication the BuiltInOAuthServerConfiguration (see below) needs to be defined with an AcceptedAudiences value other than the default.&lt;br /&gt;
|-&lt;br /&gt;
||BuiltInOAuthServerConfiguration&lt;br /&gt;
||Used to configure OAuth 2.0 compatible OAuth server settings for OAuth server built-in to ProcessAnalyzer server. If not set, built-in OAuth server functionality is disabled and clients can&#039;t connect to this server using OAuth. If set, contains a string representation of a JSON object that supports the following properties: &lt;br /&gt;
* &#039;&#039;&#039;Issuer&#039;&#039;&#039; (string): OAuth issuer, which identifies a trusted authorization server that authenticates users and issues OAuth 2.0 access tokens and JSON Web Tokens (JWTs). If not defined or empty, default value is used, which is of format: &amp;lt;QPR ProcessAnalyzer server&#039;s base URL&amp;gt;/builtin-oauth. For example: https://example.com/builtin-oauth. The default value is empty.&lt;br /&gt;
* &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; (array of strings): Array of strings that define all the accepted audiences this QPR ProcessAnalyzer server is serving. When authorizing user using OAuth, these values are matched with the audience-parameter (a.k.a. client id) of the authorization. Only requests with a value that matches a value in this array are accepted. If null, audience-parameters are not validated at all. Instead, all authorization requests will pass the audience validation check. This also enables [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)]. The default value is an empty array.&lt;br /&gt;
* &#039;&#039;&#039;SigningKey&#039;&#039;&#039; (string): Signing key for the built-in OAuth identity provider. If empty, generates a non-deterministic key based on the physical system where QPR ProcessAnalyzer is running. NOTE: Once QPR ProcessAnalyzer server is restarted, these non-deterministic keys no longer work. If defined, string must contain the key either in PEM ([https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rsa.importfrompem?view=net-10.0 RFC 7468 PEM-encoded key]) or JSON ([https://datatracker.ietf.org/doc/html/rfc7517 RFC 7517]) format. The default value is empty.&lt;br /&gt;
* &#039;&#039;&#039;TokenLifetimeSeconds&#039;&#039;&#039; (integer): Token lifetime in seconds for the built-in OAuth identity provider. After access token created by built-in gets older than this lifetime, it becomes unusable and a new token has to be created. The default value is 3600.&lt;br /&gt;
* &#039;&#039;&#039;RefreshTokenLifetimeSeconds&#039;&#039;&#039; (integer): Refresh token lifetime in seconds for the built-in OAuth identity provider. After a refresh token gets older than this lifetime, it becomes unusable and the user has to authenticate again. The default value is 2592000 (30 days).&lt;br /&gt;
* &#039;&#039;&#039;DisableExternalOAuthForwarding&#039;&#039;&#039; (boolean): Can be used to disable forwarding OAuth requests to any configured external OAuth authorization server or SAML identity provider. If set, a QPR ProcessAnalyzer&#039;s own login view functionality is always used when authorizing a user. The default value is false.&lt;br /&gt;
* &#039;&#039;&#039;ClientCredentials&#039;&#039;&#039; (array of objects):  List of confidential client registrations for the &#039;&#039;client_credentials&#039;&#039; grant type. Each entry maps a client application (identified by &#039;&#039;ClientId&#039;&#039; and &#039;&#039;ClientSecret&#039;&#039;) to a ProcessAnalyzer user, enabling machine-to-machine authentication without interactive login. If not defined or empty, the &#039;&#039;client_credentials&#039;&#039; grant type is not available. Each object in the array supports the following properties:&lt;br /&gt;
** &#039;&#039;&#039;ClientId&#039;&#039;&#039; (string): The unique client identifier used in the &#039;&#039;client_id&#039;&#039; parameter of the token request.&lt;br /&gt;
** &#039;&#039;&#039;ClientSecret&#039;&#039;&#039; (string): The client secret used to authenticate the client in the &#039;&#039;client_secret&#039;&#039; parameter of the token request. Also supports HTTP Basic authentication (&#039;&#039;Authorization: Basic base64(client_id:client_secret)&#039;&#039;).&lt;br /&gt;
** &#039;&#039;&#039;MappedUserLoginName&#039;&#039;&#039; (string): The login name of the ProcessAnalyzer user this client acts as. The issued access token will represent this user and carry their identity and permissions. The user must exist and be active in ProcessAnalyzer.&lt;br /&gt;
** &#039;&#039;&#039;Description&#039;&#039;&#039; (string): Optional human-readable description for this client registration.&lt;br /&gt;
Example ClientCredentials definition:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;ClientCredentials&amp;quot;: [&lt;br /&gt;
              {&lt;br /&gt;
                &amp;quot;ClientId&amp;quot;: &amp;quot;my-backend-service&amp;quot;,&lt;br /&gt;
                &amp;quot;ClientSecret&amp;quot;: &amp;quot;a-secure-random-secret&amp;quot;,&lt;br /&gt;
                &amp;quot;MappedUserLoginName&amp;quot;: &amp;quot;service-account&amp;quot;,&lt;br /&gt;
                &amp;quot;Description&amp;quot;: &amp;quot;Backend integration service&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
            ]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example BuiltInOAuthServerConfiguration configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Issuer&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
  &amp;quot;AcceptedAudiences&amp;quot;: [&amp;quot;qpr-processanalyzer&amp;quot;],&lt;br /&gt;
  &amp;quot;SigningKey&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
  &amp;quot;TokenLifetime&amp;quot;: 3600&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== In-memory Calculation Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||NumberOfParallelModelReaders&lt;br /&gt;
||4&lt;br /&gt;
||Models and datatable contents can be loaded with multiple simultaneous connections to the database to speed up the loading. This setting determines how many parallel loaders/readers at maximum (loaders are loading at the same time). For smaller models there are less parallel loaders than the defined limit: If there are less than 100000 rows in the table, there is only one loader. If there are less than 200000 rows in the table, there are only two loaders, and so on. &lt;br /&gt;
&lt;br /&gt;
The more there are parallel loaders, the more processor load and network bandwidth is consumed, and other operations in QPR ProcessAnalyzer might slow down. Note also that the performance optimum is achieved with a certain number of parallel loaders which differs between environment. Thus to achieve the best performance, data loading should be tested with different number of parallel loaders. Increasing number of parallel loaders beyond the optimum decreases the performance.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
||StartupModelLoadingMaxParallelism&lt;br /&gt;
||2&lt;br /&gt;
||Maximum number of QPR ProcessAnalyzer models that are loaded into memory simultaneously by the [[Automatic_Model_Loading_on_Server_Startup|Automatic Loading on Server Startup]]. If there are more models to be loaded on the server startup than this setting, loading for the rest of the models is started one by one when previous model loadings are completed. If this setting is not defined, &#039;&#039;&#039;2&#039;&#039;&#039; is used as a default value.&lt;br /&gt;
&lt;br /&gt;
Loading more models at the same time will speed up the whole model loading process, but on the other hand, it causes more load on the system, which affects the system responsiveness for users. Model loading consists of (1) transferring data from the datasource to QPR ProcessAnalyzer and (2) loaded data preprocessing into a model. The former uses mainly network bandwidth (if datasource is in a different server) and the latter uses mainly processor capacity in the QPR ProcessAnalyzer server. &lt;br /&gt;
&lt;br /&gt;
This setting affects only the model loading during the server startup and it doesn&#039;t restrict models loadings initiated by users.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== SAML 2.0 Federated Authentication Settings ==&lt;br /&gt;
Note that the SAMLMetadataUrl and ServiceProviderLocation are mandatory for the federated authentication to work. Having both ExternalOAuthServerConfiguration and SAML authentication configured at the same time is not supported.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||SAMLMetadataUrl&lt;br /&gt;
||&lt;br /&gt;
Metadata URL of the identity provider (IdP). Check that the metadata url can actually be opened using a web browser and is publicly available. The metadata is an XML document starting with &#039;&#039;&#039;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&#039;&#039;&#039; followed by an &#039;&#039;&#039;EntityDescriptor&#039;&#039;&#039; tag. The metadata URL might look &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;https://your.federated.identity.provider.com/saml/metadata&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;. This setting is mandatory for the SAML authentication to work.&lt;br /&gt;
|-&lt;br /&gt;
||ServiceProviderLocation&lt;br /&gt;
||&lt;br /&gt;
Specifies the QPR ProcessAnalyzer server location (the root path which contains e.g. the &#039;&#039;ui&#039;&#039; folder). It&#039;s used by the url to redirect back to QPR ProcessAnalyzer after a successful authentication from the identity provider. The setting is defined in the following form: &#039;&#039;&#039;https://&amp;lt;hostname&amp;gt;/qprpa&#039;&#039;&#039;, for example &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;https://customer.onqpr.com/qprpa&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;. Note that the actual redirect back url is &#039;&#039;&#039;https://&amp;lt;hostname&amp;gt;/qprpa/api/Saml2/Acs&#039;&#039;&#039; (/api/Saml2/Acs is automatically included to the url). This setting is mandatory for the SAML authentication to work. Note that if this reply url is configured the identity provider, it must match with the ServiceProviderLocation setting.&lt;br /&gt;
|-&lt;br /&gt;
||SAMLUserIdAttribute&lt;br /&gt;
||&lt;br /&gt;
Name of the SAML attribute in the assertion that will be used as the user&#039;s login name. If this field is not defined, the &#039;&#039;&#039;saml:Assertion&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:Subject&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:NameID&#039;&#039;&#039; attribute in the assertion is used. If this setting is given, one of the &#039;&#039;&#039;saml:Assertion&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:AttributeStatement&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:Attribute&#039;&#039;&#039; elements in the assertion is used (the &#039;&#039;&#039;Name&#039;&#039;&#039; attribute in the &#039;&#039;&#039;saml:Attribute&#039;&#039;&#039; element is used for matching). Please note that the saml:NameID element is different than the usual SAML attributes that are defined by the saml:Attribute elements. For example, if an email address is used as a user id, the value of the setting could be for example &#039;&#039;&amp;lt;nowiki&amp;gt;http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress&amp;lt;/nowiki&amp;gt;&#039;&#039;.&lt;br /&gt;
|-&lt;br /&gt;
||SAMLGroupsAttribute&lt;br /&gt;
||Attribute name in SAML assertion that is mapped to user groups in QPR ProcessAnalyzer. The user group names are case sensitive. When a user logs in, the user is added to and removed from groups based on the information in the SAML assertion. If this setting is not configured, users are not added to or removed from groups automatically. Note that the user needs to login for the groups to be synchronized. If a group doesn&#039;t exist in QPR ProcessAnalyzer, that group is skipped.&lt;br /&gt;
&lt;br /&gt;
In the SAML assertion, attributes are in the saml:Assertion &amp;gt; saml:AttributeStatement &amp;gt; saml:Attribute elements (the Name attribute in the saml:Attribute element is used for matching).&lt;br /&gt;
|-&lt;br /&gt;
||SAMLEncryptionCertificate&lt;br /&gt;
||This setting defines a PFX formatted X.509 certificate (defined in RCF 1422) used to encrypt SAML assertions. The public key of the certificate is published in the service provider metadata, where the identity provider can read it and encrypt SAML assertions. QPR ProcessAnalyzer as the service provider uses the corresponding private key of the certificate to decrypt SAML assertions. The setting needs to be a PFX formatted certificate file that is base64 encoded and it doesn&#039;t contain the BEGIN CERTIFICATE etc. header or footer lines. This setting is needed only when using the SAML assertions encryption. Even though this setting is defined, the SAML assertions are not required to be encrypted. More information how to create the certificate file (https://stackoverflow.com/questions/16480846/x-509-private-public-key) and convert it to base64 (https://stackoverflow.com/questions/46959822/base-64-encoded-form-of-the-pfx-file).&lt;br /&gt;
|-&lt;br /&gt;
||SAMLSigningCertificate&lt;br /&gt;
||This setting defines a PFX formatted X.509 certificate (defined in RCF 1422) used to sign SAML authentication requests sent from QPR ProcessAnalyzer to the identity provider. The public key of the certificate is published in the service provider metadata, where the identity provider can read it, to verify the authenticity of the SAML requests. The setting needs to be a PFX formatted certificate file that is base64 encoded and it doesn&#039;t contain the BEGIN CERTIFICATE etc. header or footer lines. If this setting is not defined, the internal hard-coded signing certificate is used. More information how to create the certificate file (https://stackoverflow.com/questions/16480846/x-509-private-public-key) and convert it to base64 (https://stackoverflow.com/questions/46959822/base-64-encoded-form-of-the-pfx-file).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== SMTP Server Settings ==&lt;br /&gt;
SMTP server settings are needed for QPR ProcessAnalyzer to send email messages. Email sending is used by the [[Email_Notifications|notifications]] and the [[Generic_Functions_in_QPR_ProcessAnalyzer#SendEmail|SendEmail]] function in the expression language.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||SmtpServer&lt;br /&gt;
||DNS name, host name or IP address of the SMTP server. Mandatory setting for the email sending to work.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpPort&lt;br /&gt;
||TCP port number of the SMTP server. If not defined, port 25 is used by default.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpAuthenticationUsername&lt;br /&gt;
||User name for authenticating to the SMTP server. If not defined, no authentication is used to connect to the SMTP server.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpFromAddress&lt;br /&gt;
||Email address where email messages sent by QPR ProcessAnalyzer appear to be coming from. This doesn&#039;t need to be a real email address, although the address used may affect email spam filters. The setting configured here is the default email address to use in following cases:&lt;br /&gt;
* &#039;&#039;From address&#039;&#039; is not set for the email notifications&lt;br /&gt;
* &#039;&#039;From&#039;&#039; parameter is not defined for the expression language &#039;&#039;SendEmail&#039;&#039; function&lt;br /&gt;
* &#039;&#039;EmailFrom&#039;&#039; parameter is not defined for the SQL Scripting SendEmail operation&lt;br /&gt;
|-&lt;br /&gt;
||SmtpAuthenticationPassword&lt;br /&gt;
||Password for authenticating to the SMTP server.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpEnableSSL&lt;br /&gt;
||Use value &#039;&#039;&#039;True&#039;&#039;&#039; or &#039;&#039;&#039;False&#039;&#039;&#039; depending whether TLS connection to the SMTP server is used or not. If not defined, &#039;&#039;False&#039;&#039; is the default value.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OAuth Client (for External OAuth Server) ==&lt;br /&gt;
Having both ExternalOAuthServerConfiguration and SAML authentication configured at the same time is not supported.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||ExternalOAuthServerConfiguration&lt;br /&gt;
||Used to configure OAuth 2.0 compatible OAuth server settings for server that is used to authenticate the user signing in to ProcessAnalyzer. If not set, external OAuth server will not be used for authentication. If set, contains a string representation of a JSON object that supports the following properties:&lt;br /&gt;
* &#039;&#039;&#039;Authority&#039;&#039;&#039; (string): OAuth authority URL for authentication. E.g., https://accounts.google.com/&lt;br /&gt;
* &#039;&#039;&#039;Audience&#039;&#039;&#039; (string): Mandatory. OAuth audience/client ID for validating OAuth tokens.&lt;br /&gt;
* &#039;&#039;&#039;AuthorizeUrlOverride&#039;&#039;&#039; (string): Override URL for the OAuth authorization endpoint. If empty or not defined, the default URL from the authority&#039;s discovery document is used.&lt;br /&gt;
* &#039;&#039;&#039;TokenUrlOverride&#039;&#039;&#039; (string): Override URL for the OAuth token endpoint. If empty or not defined, the default URL from the authority&#039;s discovery document is used.&lt;br /&gt;
* &#039;&#039;&#039;UserInfoUrlOverride&#039;&#039;&#039; (string): Override URL to fetch user information from the OAuth provider. If empty or not defined, the default URL from the authority&#039;s discovery document is used. Should not be used if OpendID Connect is to be used as access token validation is skipped.&lt;br /&gt;
* &#039;&#039;&#039;ClientSecret&#039;&#039;&#039; (string): OAuth client secret for confidential client authentication. If configured, this value is sent as the client_secret parameter when exchanging authorization codes for tokens.&lt;br /&gt;
* &#039;&#039;&#039;Issuer&#039;&#039;&#039; (string): OAuth issuer for validating OAuth tokens. If empty, the authority URL&#039;s issuer is used.&lt;br /&gt;
* &#039;&#039;&#039;UserNameClaim&#039;&#039;&#039; (string): Name of the claim whose value is to be used as the name of the authenticated user. The default value is &amp;quot;preferred_username&amp;quot;.&lt;br /&gt;
* &#039;&#039;&#039;UserGroupsClaim&#039;&#039;&#039; (string): Name of the claim whose value is to be used as the names of the user groups the authenticated user belongs to. When a user logs in, the user is added to and removed from groups based on the information in the UserGroupsClaim. If this setting is not configured, users are not added to or removed from groups automatically. Note that the user needs to login for the groups to be synchronized. If a group doesn&#039;t exist in QPR ProcessAnalyzer, that group is skipped. The default value is empty, i.e. groups are not synchronized.&amp;lt;br&amp;gt;&lt;br /&gt;
Example configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Authority&amp;quot;: &amp;quot;https://accounts.google.com/&amp;quot;,&lt;br /&gt;
  &amp;quot;Audience&amp;quot;: &amp;quot;...&amp;quot;,&lt;br /&gt;
  &amp;quot;ClientSecret&amp;quot;: &amp;quot;...&amp;quot;,&lt;br /&gt;
  &amp;quot;UserNameClaim&amp;quot;: &amp;quot;name&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Readonly Information ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;DatabaseVersion&amp;lt;/span&amp;gt;&lt;br /&gt;
||Database schema version. It will be updated automatically when the newer version of QPR ProcessAnalyzer Server connects to the database and performs migration for the database schema.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;InitializationScriptDatabaseVersion&amp;lt;/span&amp;gt;&lt;br /&gt;
||Database version that was when the database was initialized when the software was installed. Do not change this setting.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;MinimumDatabaseVersion&amp;lt;/span&amp;gt;&lt;br /&gt;
||Minimum allowed database version for QPR ProcessAnalyzer Server connecting to the database. This is a legacy setting and it should not be used.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28198</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28198"/>
		<updated>2026-04-27T12:13:40Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-64041&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API key. Both the authentication methods can be configured at the same time to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication, set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_CONFIGURATION database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
Some clients use the [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint: /.well-known/openid-configuration. To get this endpoint working when QPR ProcessAnalyzer is hosted in Windows in IIS, the following setup is required:&lt;br /&gt;
&lt;br /&gt;
Add an IIS rewrite rule and a CORS header at the IIS root-level &#039;&#039;&#039;web.config&#039;&#039;&#039;. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
== Creating MCP Tools ==&lt;br /&gt;
MCP tools are implemented using [[Managing_Scripts|scripts]] written in QPR ProcessAnalyzer expression language. A script will be added as the MCP tool when the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox is enabled in the [[Managing_Scripts#Script_Properties|Script Properties]]. Only system administrator users can enable the MCP tool checkbox. Also, scripts that are MCP tools, only system administrators can modify them because any changes to the MCP interface is restricted to system administrators for security reasons.&lt;br /&gt;
&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# Open or create the script.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab and select the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;Description&#039;&#039;&#039; tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
=== MCP Tool Configuration ===&lt;br /&gt;
Every script can define its own &#039;&#039;&#039;McpTool&#039;&#039;&#039; configuration as JSON. Supported values are same as [https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool here], except for the &#039;&#039;&#039;name&#039;&#039;&#039; which is always generated automatically and can&#039;t be overridden. Defining the McpTool configuration will override any default configurations generated for scripts automatically by QPR ProcessAnalyzer. For example, specifying the value for &amp;quot;title&amp;quot; here will override the default functionality of using script&#039;s name as title of the tool.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following JSON configures the MCP tool with a customized title and description, as well as some additional [https://github.com/modelcontextprotocol/csharp-sdk/blob/main/src/ModelContextProtocol.Core/Protocol/ToolAnnotations.cs MCP tool annotations]:&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Example MCP tool title&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Example MCP tool description&amp;quot;,&lt;br /&gt;
    &amp;quot;annotations&amp;quot;: {&lt;br /&gt;
        &amp;quot;destructiveHint&amp;quot;: true,&lt;br /&gt;
        &amp;quot;idempotentHint&amp;quot;: true,&lt;br /&gt;
        &amp;quot;openWorldHint&amp;quot;: true,&lt;br /&gt;
        &amp;quot;readOnlyHint&amp;quot;: false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Defining Input Parameters ===&lt;br /&gt;
MCP tool input parameters are defined using a JSON schema following the [https://modelcontextprotocol.io/specification/2025-11-25/basic#json-schema-usage Model Context Protocol&#039;s JSON Schema]. Each supported input parameter is listed under &#039;&#039;&#039;properties&#039;&#039;&#039;. By default, script don&#039;t enforce any schema.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following schema defines a script with five different types of parameters:&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;stringParameter&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;String parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
	&amp;quot;numberParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;number&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Number parameter&amp;quot;&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;booleanParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;boolean&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Boolean parameter&amp;quot;&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;arrayParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Array parameter&amp;quot;,&lt;br /&gt;
	  &amp;quot;nullable&amp;quot;: true,&lt;br /&gt;
	  &amp;quot;items&amp;quot;: {&lt;br /&gt;
		  &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
	  }&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;objectParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Object parameter&amp;quot;,&lt;br /&gt;
	  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
	    &amp;quot;inner&amp;quot;: {&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;}&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
After this, the tool can be called, for example, with the following set of parameters:&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;stringParameter&amp;quot;: &amp;quot;hello&amp;quot;,&lt;br /&gt;
  &amp;quot;numberParameter&amp;quot;: 123.456,&lt;br /&gt;
  &amp;quot;booleanParameter&amp;quot;: true,&lt;br /&gt;
  &amp;quot;arrayParameter&amp;quot;: [ 1, 2, 3 ],&lt;br /&gt;
  &amp;quot;objectParameter&amp;quot;: { &amp;quot;inner&amp;quot;: &amp;quot;test&amp;quot; }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Defining Structured Tool Output ===&lt;br /&gt;
Structured tool output is described using a JSON schema following the [https://modelcontextprotocol.io/specification/2025-11-25/basic#json-schema-usage Model Context Protocol&#039;s JSON Schema]. By default, scripts don&#039;t enforce any schema and the result is considered to be just text.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following example configures the script&#039;s return value to contain an object having the &amp;quot;models&amp;quot; property with information about each model:&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;string&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;String value&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;number&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;number&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;Number value&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;boolean&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;boolean&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;Boolean value&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;array&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;Array value&amp;quot;,&lt;br /&gt;
      &amp;quot;nullable&amp;quot;: true,&lt;br /&gt;
      &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;object&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;Object value&amp;quot;,&lt;br /&gt;
      &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;inner&amp;quot;: {&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;}&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
== Testing MCP tools in QPR ProcessAnalyzer ==&lt;br /&gt;
When developing MCP tools, it might be useful try test them in QPR ProcessAnalyzer before publishing as MCP tools. Scripts (used as MCP tools) can be called in the [[Navigation_Menu#Expression_Designer|Expression Designer]]. The following example expression calls a script with some parameters and shows the return value as json:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
let returnValue = ScriptById(1).Run(#{&lt;br /&gt;
  &amp;quot;stringParameter&amp;quot;: &amp;quot;hello&amp;quot;,&lt;br /&gt;
  &amp;quot;numberParameter&amp;quot;: 123.456,&lt;br /&gt;
  &amp;quot;booleanParameter&amp;quot;: true,&lt;br /&gt;
  &amp;quot;arrayParameter&amp;quot;: [1, 2, 3]&lt;br /&gt;
  &amp;quot;objectParameter&amp;quot;: {&lt;br /&gt;
    &amp;quot;inner&amp;quot;: &amp;quot;test&amp;quot;&lt;br /&gt;
  }&lt;br /&gt;
});&lt;br /&gt;
return ToJson(returnValue);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now, if script having id 1 has the following script source code:&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
#{&lt;br /&gt;
  &amp;quot;string&amp;quot;: stringParameter,&lt;br /&gt;
  &amp;quot;number&amp;quot;: numberParameter,&lt;br /&gt;
  &amp;quot;boolean&amp;quot;: booleanParameter,&lt;br /&gt;
  &amp;quot;array&amp;quot;: arrayParameter,&lt;br /&gt;
  &amp;quot;object&amp;quot;: objectParameter&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and is configured as specified in the previous chapter, the result of expression will be the following valid JSON object as string:&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;string&amp;quot;: &amp;quot;hello&amp;quot;,&lt;br /&gt;
  &amp;quot;number&amp;quot;: 123.456,&lt;br /&gt;
  &amp;quot;boolean&amp;quot;: true,&lt;br /&gt;
  &amp;quot;array&amp;quot;: [1,2,3],&lt;br /&gt;
  &amp;quot;object&amp;quot;: {&amp;quot;inner&amp;quot;: &amp;quot;text&amp;quot;}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_CONFIGURATION database table.&lt;br /&gt;
* &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_CONFIGURATION database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)]. This is often automatically done by MCP Client software.&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
* Connect to Server: &lt;br /&gt;
** In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., https://your-pa-server/qprpa/api/mcp)&lt;br /&gt;
** Select Streamable HTTP as the transport type.&lt;br /&gt;
** Select &amp;quot;Via Proxy&amp;quot; as connection type.&lt;br /&gt;
* Authenticate: &lt;br /&gt;
** If using API Key-based authentication, configure &amp;quot;X-Mcp-Api-Key&amp;quot; as additional custom header with the value specified in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting of the PA server.&lt;br /&gt;
** If using OAuth, set one of the accepted audience values to Authentication/OAuth 2.0 Flow/Client ID (or leave it empty if DCR is enabled).&lt;br /&gt;
*** Open Auth Settings&lt;br /&gt;
*** Click &amp;quot;Quick OAuth Flow&amp;quot;-button.&lt;br /&gt;
**** Perform OAuth authorization using the built-in OAuth provider.&lt;br /&gt;
**** Provided that the authentication has been configured correctly, a successful authentication message should be shown.&lt;br /&gt;
** Click Connect.&lt;br /&gt;
* List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool created for a parameterless QPR ProcessAnalyzer script having id 216, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
  &amp;quot;params&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Script-216&amp;quot;,&lt;br /&gt;
    &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
    &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
      &amp;quot;progressToken&amp;quot;: 0&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28192</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28192"/>
		<updated>2026-04-27T11:42:48Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-64041&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API key. Both the authentication methods can be configured at the same time to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication, set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_CONFIGURATION database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
Some clients use the [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint: /.well-known/openid-configuration. To get this endpoint working when QPR ProcessAnalyzer is hosted in Windows in IIS, the following setup is required:&lt;br /&gt;
&lt;br /&gt;
Add an IIS rewrite rule and a CORS header at the IIS root-level &#039;&#039;&#039;web.config&#039;&#039;&#039;. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
== Creating MCP Tools ==&lt;br /&gt;
MCP tools are implemented using [[Managing_Scripts|scripts]] written in QPR ProcessAnalyzer expression language. A script will be added as the MCP tool when the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox is enabled in the [[Managing_Scripts#Script_Properties|Script Properties]]. Only system administrator users can enable the MCP tool checkbox. Also, scripts that are MCP tools, only system administrators can modify them because any changes to the MCP interface is restricted to system administrators for security reasons.&lt;br /&gt;
&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# Open or create the script.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab and select the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;Description&#039;&#039;&#039; tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
=== MCP Tool Configuration ===&lt;br /&gt;
Every script can define its own &#039;&#039;&#039;McpTool&#039;&#039;&#039; configuration as JSON. Supported values are same as [https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool here], except for the &#039;&#039;&#039;name&#039;&#039;&#039; which is always generated automatically and can&#039;t be overridden. Defining the McpTool configuration will override any default configurations generated for scripts automatically by QPR ProcessAnalyzer. For example, specifying the value for &amp;quot;title&amp;quot; here will override the default functionality of using script&#039;s name as title of the tool.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following JSON configures the MCP tool with a customized title and description, as well as some additional [https://github.com/modelcontextprotocol/csharp-sdk/blob/main/src/ModelContextProtocol.Core/Protocol/ToolAnnotations.cs MCP tool annotations]:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Example MCP tool title&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Example MCP tool description&amp;quot;,&lt;br /&gt;
    &amp;quot;annotations&amp;quot;: {&lt;br /&gt;
        &amp;quot;destructiveHint&amp;quot;: true,&lt;br /&gt;
        &amp;quot;idempotentHint&amp;quot;: true,&lt;br /&gt;
        &amp;quot;openWorldHint&amp;quot;: true,&lt;br /&gt;
        &amp;quot;readOnlyHint&amp;quot;: false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Defining Input Parameters ===&lt;br /&gt;
MCP tool input parameters are defined using a JSON schema following the [https://modelcontextprotocol.io/specification/2025-11-25/basic#json-schema-usage Model Context Protocol&#039;s JSON Schema]. Each supported input parameter is listed under &#039;&#039;&#039;properties&#039;&#039;&#039;. By default, script don&#039;t enforce any schema.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following schema defines a script with five different types of parameters:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;stringParameter&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;String parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
	&amp;quot;numberParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;number&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Number parameter&amp;quot;&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;booleanParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;boolean&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Boolean parameter&amp;quot;&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;arrayParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Array parameter&amp;quot;,&lt;br /&gt;
	  &amp;quot;nullable&amp;quot;: true,&lt;br /&gt;
	  &amp;quot;items&amp;quot;: {&lt;br /&gt;
		  &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
	  }&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;objectParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Object parameter&amp;quot;,&lt;br /&gt;
	  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
	    &amp;quot;inner&amp;quot;: {&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;}&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
After this, the tool can be called, for example, with the following set of parameters:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;stringParameter&amp;quot;: &amp;quot;bar&amp;quot;,&lt;br /&gt;
  &amp;quot;numberParameter&amp;quot;: 123.456,&lt;br /&gt;
  &amp;quot;booleanParameter&amp;quot;: true,&lt;br /&gt;
  &amp;quot;arrayParameter&amp;quot;: [ 1, 2, 3 ],&lt;br /&gt;
  &amp;quot;objectParameter&amp;quot;: { &amp;quot;inner&amp;quot;: &amp;quot;test&amp;quot; }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Defining Structured Tool Output ===&lt;br /&gt;
Structured tool output is described using a JSON schema following the [https://modelcontextprotocol.io/specification/2025-11-25/basic#json-schema-usage Model Context Protocol&#039;s JSON Schema]. By default, scripts don&#039;t enforce any schema and the result is considered to be just text.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following example configures the script&#039;s return value to contain an object having the &amp;quot;models&amp;quot; property with information about each model:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;models&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;Array of models&amp;quot;,&lt;br /&gt;
      &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: {&lt;br /&gt;
          &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Unique model identifier&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Name of the model&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Description of a model&amp;quot;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing MCP tools in QPR ProcessAnalyzer ==&lt;br /&gt;
When developing MCP tools, it might be useful try test them in QPR ProcessAnalyzer before publishing as MCP tools. Scripts (used as MCP tools) can be called in the [[Navigation_Menu#Expression_Designer|Expression Designer]]. The following example expression calls a script with some parameters and shows the return value as json:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot; line&amp;gt;&lt;br /&gt;
let returnValue = ScriptById(1).Run(#{&lt;br /&gt;
  &amp;quot;string_param&amp;quot;: &amp;quot;value1&amp;quot;,&lt;br /&gt;
  &amp;quot;integer_param&amp;quot;: 123,&lt;br /&gt;
  &amp;quot;boolean_param&amp;quot;: false,&lt;br /&gt;
  &amp;quot;array_param&amp;quot;: [&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;]&lt;br /&gt;
});&lt;br /&gt;
return ToJson(returnValue);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_CONFIGURATION database table.&lt;br /&gt;
* &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_CONFIGURATION database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)]. This is often automatically done by MCP Client software.&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
* Connect to Server: &lt;br /&gt;
** In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., https://your-pa-server/qprpa/api/mcp)&lt;br /&gt;
** Select Streamable HTTP as the transport type.&lt;br /&gt;
** Select &amp;quot;Via Proxy&amp;quot; as connection type.&lt;br /&gt;
* Authenticate: &lt;br /&gt;
** If using API Key-based authentication, configure &amp;quot;X-Mcp-Api-Key&amp;quot; as additional custom header with the value specified in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting of the PA server.&lt;br /&gt;
** If using OAuth, set one of the accepted audience values to Authentication/OAuth 2.0 Flow/Client ID (or leave it empty if DCR is enabled).&lt;br /&gt;
*** Open Auth Settings&lt;br /&gt;
*** Click &amp;quot;Quick OAuth Flow&amp;quot;-button.&lt;br /&gt;
**** Perform OAuth authorization using the built-in OAuth provider.&lt;br /&gt;
**** Provided that the authentication has been configured correctly, a successful authentication message should be shown.&lt;br /&gt;
** Click Connect.&lt;br /&gt;
* List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool created for a parameterless QPR ProcessAnalyzer script having id 216, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
  &amp;quot;params&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Script-216&amp;quot;,&lt;br /&gt;
    &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
    &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
      &amp;quot;progressToken&amp;quot;: 0&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28191</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28191"/>
		<updated>2026-04-27T11:37:04Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-64041&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API key. Both the authentication methods can be configured at the same time to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication, set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_CONFIGURATION database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
Some clients use the [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint: /.well-known/openid-configuration. To get this endpoint working when QPR ProcessAnalyzer is hosted in Windows in IIS, the following setup is required:&lt;br /&gt;
&lt;br /&gt;
Add an IIS rewrite rule and a CORS header at the IIS root-level &#039;&#039;&#039;web.config&#039;&#039;&#039;. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
== Creating MCP Tools ==&lt;br /&gt;
MCP tools are implemented using [[Managing_Scripts|scripts]] written in QPR ProcessAnalyzer expression language. A script will be added as the MCP tool when the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox is enabled in the [[Managing_Scripts#Script_Properties|Script Properties]]. Only system administrator users can enable the MCP tool checkbox. Also, scripts that are MCP tools, only system administrators can modify them because any changes to the MCP interface is restricted to system administrators for security reasons.&lt;br /&gt;
&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# Open or create the script.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab and select the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;Description&#039;&#039;&#039; tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
=== MCP Tool Configuration ===&lt;br /&gt;
Every script can define its own &#039;&#039;&#039;McpTool&#039;&#039;&#039; configuration as JSON. Supported values are same as [https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool here], except for the &#039;&#039;&#039;name&#039;&#039;&#039; which is always generated automatically and can&#039;t be overridden. Defining the McpTool configuration will override any default configurations generated for scripts automatically by QPR ProcessAnalyzer. For example, specifying the value for &amp;quot;title&amp;quot; here will override the default functionality of using script&#039;s name as title of the tool.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following JSON configures the MCP tool with a customized title and description, as well as some additional [https://github.com/modelcontextprotocol/csharp-sdk/blob/main/src/ModelContextProtocol.Core/Protocol/ToolAnnotations.cs MCP tool annotations]:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Example MCP tool title&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Example MCP tool description&amp;quot;,&lt;br /&gt;
    &amp;quot;annotations&amp;quot;: {&lt;br /&gt;
        &amp;quot;destructiveHint&amp;quot;: true,&lt;br /&gt;
        &amp;quot;idempotentHint&amp;quot;: true,&lt;br /&gt;
        &amp;quot;openWorldHint&amp;quot;: true,&lt;br /&gt;
        &amp;quot;readOnlyHint&amp;quot;: false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Defining Input Parameters ===&lt;br /&gt;
MCP tool input parameters are defined using a JSON schema following the [https://modelcontextprotocol.io/specification/2025-11-25/basic#json-schema-usage Model Context Protocol&#039;s JSON Schema]. Each supported input parameter is listed under &#039;&#039;&#039;properties&#039;&#039;&#039;. By default, script don&#039;t enforce any schema.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following schema defines a script with five different types of parameters:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;stringParameter&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;String parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
	&amp;quot;numberParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;number&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Number parameter&amp;quot;&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;booleanParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;boolean&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Boolean parameter&amp;quot;&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;arrayParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Array parameter&amp;quot;,&lt;br /&gt;
	  &amp;quot;nullable&amp;quot;: true,&lt;br /&gt;
	  &amp;quot;items&amp;quot;: {&lt;br /&gt;
		  &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
	  }&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;objectParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Object parameter&amp;quot;,&lt;br /&gt;
	  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
	    &amp;quot;inner&amp;quot;: {&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;}&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
After this, the tool can be called, for example, with the following set of parameters:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;stringParameter&amp;quot;: &amp;quot;bar&amp;quot;,&lt;br /&gt;
  &amp;quot;numberParameter&amp;quot;: 123.456,&lt;br /&gt;
  &amp;quot;booleanParameter&amp;quot;: true,&lt;br /&gt;
  &amp;quot;arrayParameter&amp;quot;: [ 1, 2, 3 ],&lt;br /&gt;
  &amp;quot;objectParameter&amp;quot;: { &amp;quot;inner&amp;quot;: &amp;quot;test&amp;quot; }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Defining Structured Tool Output ===&lt;br /&gt;
Structured tool output is described using a JSON schema following the [https://modelcontextprotocol.io/specification/2025-11-25/basic#json-schema-usage Model Context Protocol&#039;s JSON Schema]. By default, scripts don&#039;t enforce any schema and the result is considered to be just text.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following example configures the script&#039;s return value to contain an object having five different types of properties.:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;string&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;String parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;number&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;number&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Number parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;boolean&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;boolean&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Boolean parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;array&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Array parameter&amp;quot;,&lt;br /&gt;
        &amp;quot;nullable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;items&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;object&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Object parameter&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;inner&amp;quot;: {&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;}&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing MCP tools in QPR ProcessAnalyzer ==&lt;br /&gt;
When developing MCP tools, it might be useful try test them in QPR ProcessAnalyzer before publishing as MCP tools. Scripts (used as MCP tools) can be called in the [[Navigation_Menu#Expression_Designer|Expression Designer]]. The following example expression calls a script with some parameters and shows the return value as json:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot; line&amp;gt;&lt;br /&gt;
let returnValue = ScriptById(1).Run(#{&lt;br /&gt;
  &amp;quot;string_param&amp;quot;: &amp;quot;value1&amp;quot;,&lt;br /&gt;
  &amp;quot;integer_param&amp;quot;: 123,&lt;br /&gt;
  &amp;quot;boolean_param&amp;quot;: false,&lt;br /&gt;
  &amp;quot;array_param&amp;quot;: [&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;]&lt;br /&gt;
});&lt;br /&gt;
return ToJson(returnValue);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_CONFIGURATION database table.&lt;br /&gt;
* &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_CONFIGURATION database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)]. This is often automatically done by MCP Client software.&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
* Connect to Server: &lt;br /&gt;
** In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., https://your-pa-server/qprpa/api/mcp)&lt;br /&gt;
** Select Streamable HTTP as the transport type.&lt;br /&gt;
** Select &amp;quot;Via Proxy&amp;quot; as connection type.&lt;br /&gt;
* Authenticate: &lt;br /&gt;
** If using API Key-based authentication, configure &amp;quot;X-Mcp-Api-Key&amp;quot; as additional custom header with the value specified in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting of the PA server.&lt;br /&gt;
** If using OAuth, set one of the accepted audience values to Authentication/OAuth 2.0 Flow/Client ID (or leave it empty if DCR is enabled).&lt;br /&gt;
*** Open Auth Settings&lt;br /&gt;
*** Click &amp;quot;Quick OAuth Flow&amp;quot;-button.&lt;br /&gt;
**** Perform OAuth authorization using the built-in OAuth provider.&lt;br /&gt;
**** Provided that the authentication has been configured correctly, a successful authentication message should be shown.&lt;br /&gt;
** Click Connect.&lt;br /&gt;
* List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool created for a parameterless QPR ProcessAnalyzer script having id 216, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
  &amp;quot;params&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Script-216&amp;quot;,&lt;br /&gt;
    &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
    &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
      &amp;quot;progressToken&amp;quot;: 0&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_Objects_in_Expression_Language&amp;diff=28190</id>
		<title>QPR ProcessAnalyzer Objects in Expression Language</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_Objects_in_Expression_Language&amp;diff=28190"/>
		<updated>2026-04-27T11:23:58Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-64041&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Filter==&lt;br /&gt;
Filters contain a set of filter rules used to filter cases and events in models. Filters are objects located in the models. Filters are owned by the creator user, and when a filter publish mode is private, only the creator can use it.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!&#039;&#039;&#039;Filter properties&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||CreatedBy (User)&lt;br /&gt;
||Returns the user who created the filter.&lt;br /&gt;
|-&lt;br /&gt;
||CreatedDate (DateTime)&lt;br /&gt;
||Returns date when the filter created date.&lt;br /&gt;
|-&lt;br /&gt;
||Description (String)&lt;br /&gt;
||Returns description of the filter.&lt;br /&gt;
|-&lt;br /&gt;
||Id (Integer)&lt;br /&gt;
||Returns id of the filter.&lt;br /&gt;
|-&lt;br /&gt;
||LastModifiedBy (User)&lt;br /&gt;
||Returns user who modified the filter.&lt;br /&gt;
|-&lt;br /&gt;
||LastModifiedDate (DateTime)&lt;br /&gt;
||Returns date when the filter last modified.&lt;br /&gt;
|-&lt;br /&gt;
||Model&lt;br /&gt;
||Returns model where the filter belongs to.&lt;br /&gt;
|-&lt;br /&gt;
||ModelId (Integer)&lt;br /&gt;
||Returns model where the filter belongs to.&lt;br /&gt;
|-&lt;br /&gt;
||Name (String)&lt;br /&gt;
||Returns the name of the filter.&lt;br /&gt;
|-&lt;br /&gt;
||Project&lt;br /&gt;
||Returns project where the filter belongs to.&lt;br /&gt;
|-&lt;br /&gt;
||ProjectId (Integer)&lt;br /&gt;
||Returns project id where the filter belongs to.&lt;br /&gt;
|-&lt;br /&gt;
||PublishMode (String)&lt;br /&gt;
||Returns publish mode of the filter, one of the following: &#039;&#039;&#039;Private&#039;&#039;&#039;, &#039;&#039;&#039;Public&#039;&#039;&#039;, or &#039;&#039;&#039;Default&#039;&#039;&#039;.&lt;br /&gt;
|-&lt;br /&gt;
||Rules (Dictionary)&lt;br /&gt;
||Returns a dictionary containing the filter rules in the filter.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!&#039;&#039;&#039;Filter functions&#039;&#039;&#039;&lt;br /&gt;
!&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||DeletePermanently&lt;br /&gt;
||(none)&lt;br /&gt;
||&lt;br /&gt;
Deletes the filter permanently. To delete own filters, the &#039;&#039;&#039;Filtering&#039;&#039;&#039; permission is needed, and to delete any filters the &#039;&#039;&#039;ManageViews&#039;&#039;&#039; permission is needed.&lt;br /&gt;
|-&lt;br /&gt;
||Modify&lt;br /&gt;
||Dictionary&lt;br /&gt;
||&lt;br /&gt;
Modifies filter properties. The parameter is a dictionary containing the properties to be changed. Following properties can be changed: &#039;&#039;Name&#039;&#039;, &#039;&#039;Description&#039;&#039;, &#039;&#039;PublishMode&#039;&#039;, and &#039;&#039;Rules&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The function returns the updated filter object. Requires &#039;&#039;GenericWrite&#039;&#039; permission for the Project and global &#039;&#039;CreateModel&#039;&#039; permission.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FilterById(1)&lt;br /&gt;
	.Modify(#{&lt;br /&gt;
		&amp;quot;Name&amp;quot;: &amp;quot;My filter&amp;quot;,&lt;br /&gt;
		&amp;quot;Description&amp;quot;: &amp;quot;My description&amp;quot;,&lt;br /&gt;
		&amp;quot;PublishMode&amp;quot;: &amp;quot;Public&amp;quot;,&lt;br /&gt;
		&amp;quot;Rules&amp;quot;: #{&lt;br /&gt;
			&amp;quot;Items&amp;quot;: [&lt;br /&gt;
				#{&lt;br /&gt;
					&amp;quot;Type&amp;quot;: &amp;quot;IncludeCases&amp;quot;,&lt;br /&gt;
					&amp;quot;Items&amp;quot;: [&lt;br /&gt;
						#{&lt;br /&gt;
							&amp;quot;Type&amp;quot;: &amp;quot;CaseAttributeValue&amp;quot;,&lt;br /&gt;
							&amp;quot;Attribute&amp;quot;: &amp;quot;Account Manager&amp;quot;,&lt;br /&gt;
							&amp;quot;StringifiedValues&amp;quot;: [&lt;br /&gt;
								&amp;quot;0Mary Wilson&amp;quot;&lt;br /&gt;
							]&lt;br /&gt;
						}&lt;br /&gt;
					]&lt;br /&gt;
				}&lt;br /&gt;
			]&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Function to get filter id:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!&#039;&#039;&#039;Functions&#039;&#039;&#039;&lt;br /&gt;
!&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||FilterById&lt;br /&gt;
||&lt;br /&gt;
* Filter id (Integer)&lt;br /&gt;
||&lt;br /&gt;
Returns Filter object corresponding to the provided filter id.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Model==&lt;br /&gt;
Notes:&lt;br /&gt;
* For in-memory models that are offline, the object counts represent the situation when the model was last time online (loaded into the memory). &#039;&#039;null&#039;&#039; is returned if the model has never been loaded into the memory.&lt;br /&gt;
* If [[Case_Level_Permissions|Case permissions]] are used for the model, and user doesn&#039;t have &#039;&#039;&#039;GenericWrite&#039;&#039;&#039; permission for the model, &#039;&#039;null&#039;&#039; is returned for data security reasons. Users that have the &#039;&#039;&#039;GenericWrite&#039;&#039;&#039; permission, see null when the model is offline, and when online, they see counts where the case level permissions settings are applied.&lt;br /&gt;
* Properties &#039;&#039;CaseAttributes&#039;&#039;, &#039;&#039;EventAttributes&#039;&#039; and &#039;&#039;Eventlog&#039;&#039; work only for the in-memory models and they require the model to be loaded into the memory. If the model is not in the memory, it is loaded when these properties is used. Other model properties down require the model to be in the memory.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!&#039;&#039;&#039;Model properties&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||AllFilters (Filter*)&lt;br /&gt;
||Returns an array of all [[#Filter|filters]] in the model where the user has access to. In addition to the &#039;&#039;Filters&#039;&#039; property, &#039;&#039;AllFilters&#039;&#039; also returns private filters of other users. The &#039;&#039;ManageViews&#039;&#039; permission is required to use this property.&lt;br /&gt;
|-&lt;br /&gt;
||Calendars (BusinessCalendar*)&lt;br /&gt;
||&lt;br /&gt;
Returns all [[Business_Calendar|business calendars]] stored to the Model as an array. Returns an empty array, if there are no business calendars stored to the model. Note: UI allows to set only one business calendar for a Model.&lt;br /&gt;
|-&lt;br /&gt;
||CaseAttributes (AttributeType*)&lt;br /&gt;
||[[#AttributeType|CaseAttributes]] in the model returned in the alphabetical order. Using this property requires that the model is loaded in the memory. If the model is not in the memory, it&#039;s loaded when this property is used.&lt;br /&gt;
|-&lt;br /&gt;
||CasesDatatable (Datatable)&lt;br /&gt;
||Returns the Datatable the model uses as a datasource for cases. Returns &#039;&#039;null&#039;&#039; if the cases Datatable is not defined or if model uses other than the Datatable datasource.&lt;br /&gt;
|-&lt;br /&gt;
||Configuration (Dictionary)&lt;br /&gt;
||Returns the Model configuration as dictionary. Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ModelById(123).Configuration.DataSource.Events.DataTableName&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||ConfigurationJson (String)&lt;br /&gt;
||Returns the Model configuration as JSON string.&lt;br /&gt;
|-&lt;br /&gt;
||CreatedBy (User)&lt;br /&gt;
||User who created the model.&lt;br /&gt;
|-&lt;br /&gt;
||CreatedDate (DateTime)&lt;br /&gt;
||Timestamp when the model was created.&lt;br /&gt;
|-&lt;br /&gt;
||DefaultCalendar (BusinessCalendar)&lt;br /&gt;
||Returns the default [[Business_Calendar|business calendar]] of the Model. Returns &#039;&#039;null&#039;&#039;, if there are no calendars in the Model or no calendar has been set as a default calendar. Note: UI allows to set only one business calendar for a Model, which is also the default calendar.&lt;br /&gt;
|-&lt;br /&gt;
||DefaultFilter (Filter)&lt;br /&gt;
||Default filter of the model. Returns &#039;&#039;null&#039;&#039; if the model does not have a default filter.&lt;br /&gt;
|-&lt;br /&gt;
||DefaultFilterId (Integer)&lt;br /&gt;
||Default filter id of the model. Returns &#039;&#039;null&#039;&#039; if the model does not have a default filter.&lt;br /&gt;
|-&lt;br /&gt;
||Description (String)&lt;br /&gt;
||Model description. The model description may contain line breaks.&lt;br /&gt;
|-&lt;br /&gt;
||DeletedDate (DateTime)&lt;br /&gt;
||Timestamp when Model was deleted (moved to the recycle bin).&lt;br /&gt;
|-&lt;br /&gt;
||DeletedBy (User)&lt;br /&gt;
||User how deleted the Model.&lt;br /&gt;
|-&lt;br /&gt;
||Diagrams (Diagram*)&lt;br /&gt;
||Returns an array of all [[Diagram_in_Expression_Language|diagrams]] in the model.&lt;br /&gt;
|-&lt;br /&gt;
||EstimatedMemory (Integer)&lt;br /&gt;
||Returns an estimation of how much memory in bytes the model requires.&lt;br /&gt;
|-&lt;br /&gt;
||EventsDatatable (Datatable)&lt;br /&gt;
||Returns the Datatable the model uses as a datasource for events. Returns &#039;&#039;null&#039;&#039; if the events Datatable is not defined or if model uses other than the Datatable datasource.&lt;br /&gt;
|-&lt;br /&gt;
||EventAttributes (AttributeType*)&lt;br /&gt;
||[[#AttributeType|EventAttributes]] in the model returned in the alphabetical order. Using this property requires that the model is loaded in the memory. If the model is not in the memory, it&#039;s loaded when this property is used.&lt;br /&gt;
|-&lt;br /&gt;
||EventLog (EventLog)&lt;br /&gt;
||EventLog containing the entire model (i.e. event log where no filters have been applied). Using this property requires that the model is loaded in the memory. If the model is not in the memory, it&#039;s loaded when this property is used.&lt;br /&gt;
|-&lt;br /&gt;
||Filters (Filter*)&lt;br /&gt;
||Returns an array of all public [[#Filter|filters]], the default filter (if any) and the user&#039;s own private filters in the model. Note that the other users&#039;s private filters are not returned even for administrators.&lt;br /&gt;
|-&lt;br /&gt;
||Id (Integer)&lt;br /&gt;
||Model Id. Model Id is generated by QPR ProcessAnalyzer when the model is created.&lt;br /&gt;
|-&lt;br /&gt;
||IsValidInMemoryModel (boolean)&lt;br /&gt;
||Returns &#039;&#039;true&#039;&#039; if all the following conditions are met:&lt;br /&gt;
* CheckModelValidity function doesn&#039;t return any issues (because invalid models are assumed to be Snowflake models).&lt;br /&gt;
* Model is not an object-centric model.&lt;br /&gt;
* Data source of the model is &#039;&#039;ODBC&#039;&#039; or &#039;&#039;Expression&#039;&#039;, or the referred datatable has &#039;&#039;DataSourceType&#039;&#039; either &#039;&#039;Local&#039;&#039; or &#039;&#039;SqlServer&#039;&#039;.&lt;br /&gt;
|-&lt;br /&gt;
||LastModifiedBy (User)&lt;br /&gt;
||User who last time modified the model properties. Note that datatables containing the eventlog data are separate objects having similar fields to track the last modification and last data import.&lt;br /&gt;
|-&lt;br /&gt;
||LastModifiedDate (DateTime)&lt;br /&gt;
||Timestamp when the model was modified the last time.&lt;br /&gt;
|-&lt;br /&gt;
||Name (String)&lt;br /&gt;
||Model name.&lt;br /&gt;
|-&lt;br /&gt;
||NCache (Integer)&lt;br /&gt;
||Number of objects related to the model when the model is loaded into the memory.&lt;br /&gt;
|-&lt;br /&gt;
||NCaseAttributes (Integer)&lt;br /&gt;
||Number of [[#AttributeType|CaseAttributes]] in model. Works only for in-memory models.&lt;br /&gt;
|-&lt;br /&gt;
||NCases (Integer)&lt;br /&gt;
||Number of [[#Case|Cases]] in the model. Works only for in-memory models.&lt;br /&gt;
|-&lt;br /&gt;
||NEventAttributes (Integer)&lt;br /&gt;
||Number of [[#AttributeType|EventAttributes]] in model. Works only for in-memory models.&lt;br /&gt;
|-&lt;br /&gt;
||NEvents (Integer)&lt;br /&gt;
||Number of [[#Event|Events]] in model. Works only for in-memory models.&lt;br /&gt;
|-&lt;br /&gt;
||NEventTypes (Integer)&lt;br /&gt;
||Number of [[#EventType|EventTypes]] in the model. Works only for in-memory models.&lt;br /&gt;
|-&lt;br /&gt;
||Project (Project)&lt;br /&gt;
||[[#Project|Project]] where the model belongs to.&lt;br /&gt;
|-&lt;br /&gt;
||ProjectId (Integer)&lt;br /&gt;
||[[#Project|Project]] id where the model belongs to.&lt;br /&gt;
|-&lt;br /&gt;
||Status (String)&lt;br /&gt;
||&lt;br /&gt;
Memory availability status of the model. There are the following statuses:&lt;br /&gt;
* &#039;&#039;&#039;Loading&#039;&#039;&#039;: The model is currently loading into the memory. When the loading is ready, the status changes to &#039;&#039;online&#039;&#039;. If the loading fails, the status changes to &#039;&#039;offline&#039;&#039;.&lt;br /&gt;
* &#039;&#039;&#039;Offline&#039;&#039;&#039;: The model is currently not loaded into the memory. The model needs to be loaded into the memory, so that analyses can be calculated from the model (occurs automatically when an analysis is requested).&lt;br /&gt;
* &#039;&#039;&#039;Online&#039;&#039;&#039;: The model is in the memory and ready for analysis calculation. If the model is dropped from the memory, its status changes to &#039;&#039;offline&#039;&#039;.&lt;br /&gt;
|-&lt;br /&gt;
||UsedDatatables (Datatable*)&lt;br /&gt;
||Returns all datatables the model uses as a datasource.&lt;br /&gt;
&lt;br /&gt;
Example: List datatables used by a model:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StringJoin(&amp;quot;, &amp;quot;, OrderByValue(ModelById(1).UsedDataTables.Name))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!&#039;&#039;&#039;Model functions&#039;&#039;&#039;&lt;br /&gt;
!&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||CalendarByName (BusinessCalendar)&lt;br /&gt;
||&lt;br /&gt;
name (String)&lt;br /&gt;
||&lt;br /&gt;
Returns a [[Business_Calendar|business calendar]] stored to the Model by the name of the calendar. Business calendars can be stored to models in the model properties. Returns &#039;&#039;null&#039;&#039;, if a calendar with the provided name is not stored to the model.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ModelById(123).CalendarByName(&amp;quot;MyCalendar&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||CreateDiagram (Diagram)&lt;br /&gt;
||Parameters dictionary&lt;br /&gt;
||&lt;br /&gt;
Creates a [[Diagram_in_Expression_Language|diagram]] to the model. Parameters is a dictionary containing diagram properties. Following properties are available:&lt;br /&gt;
* &#039;&#039;&#039;Name&#039;&#039;&#039; (string): Diagram name that distinguishes diagrams in a model.&lt;br /&gt;
* &#039;&#039;&#039;Description&#039;&#039;&#039; (string): Diagram description text.&lt;br /&gt;
* &#039;&#039;&#039;Content&#039;&#039;&#039; (dictionary): Diagram content as dictionary.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ModelById(1)&lt;br /&gt;
  .CreateDiagram(#{&lt;br /&gt;
    &amp;quot;Name&amp;quot;: &amp;quot;My diagram&amp;quot;,&lt;br /&gt;
    &amp;quot;Description&amp;quot;: &amp;quot;This is my new diagram&amp;quot;,&lt;br /&gt;
    &amp;quot;Content&amp;quot;: #{ ... },&lt;br /&gt;
  })&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||CreateFilter (Filter)&lt;br /&gt;
||Parameters dictionary&lt;br /&gt;
||Creates a filter to a model. Requires &#039;&#039;GenericWrite&#039;&#039; permission for the project and global &#039;&#039;CreateModel&#039;&#039; permission. If a filter with that name already exists in the model, an exception is thrown.&lt;br /&gt;
The parameters dictionary may have the following properties:&lt;br /&gt;
* &#039;&#039;&#039;Name&#039;&#039;&#039;: Name of the filter. This property is mandatory.&lt;br /&gt;
* &#039;&#039;&#039;Description&#039;&#039;&#039;: Description of the filter. This property is optional.&lt;br /&gt;
* &#039;&#039;&#039;Rules&#039;&#039;&#039;: Filter rules for the filter defined as a dictionary according to the [[Filtering_in_QPR_ProcessAnalyzer_Queries|filter json format]]. This property is mandatory.&lt;br /&gt;
* &#039;&#039;&#039;PublishMode&#039;&#039;&#039;: Publish mode of the filter which is one of the following: &#039;&#039;Private&#039;&#039;, &#039;&#039;Public&#039;&#039; or &#039;&#039;Default&#039;&#039;. This property is optional, and the default value is &#039;&#039;Private&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
let newFilter = modelById(1).CreateFilter(#{    &lt;br /&gt;
  &amp;quot;Name&amp;quot;: &amp;quot;My Filter&amp;quot;,&lt;br /&gt;
  &amp;quot;Rules&amp;quot;: #{&lt;br /&gt;
    &amp;quot;Items&amp;quot;: [#{&lt;br /&gt;
      &amp;quot;Type&amp;quot;: &amp;quot;IncludeCases&amp;quot;,&lt;br /&gt;
      &amp;quot;Items&amp;quot;: [#{&lt;br /&gt;
        &amp;quot;Type&amp;quot;: &amp;quot;CaseAttributeValue&amp;quot;,&lt;br /&gt;
        &amp;quot;Attribute&amp;quot;: &amp;quot;Account Manager&amp;quot;,&lt;br /&gt;
        &amp;quot;StringifiedValues&amp;quot;: [ &amp;quot;0Robert Miller&amp;quot; ]&lt;br /&gt;
      }]&lt;br /&gt;
    }]&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;PublishMode&amp;quot;: &amp;quot;Public&amp;quot;&lt;br /&gt;
});&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||DeletePermanently&lt;br /&gt;
||(none)&lt;br /&gt;
||Deletes the Model permanently. The model doesn&#039;t need to be in the recycle bin to be able to delete it permanently.&lt;br /&gt;
|-&lt;br /&gt;
||Modify (Model)&lt;br /&gt;
||Dictionary&lt;br /&gt;
||&lt;br /&gt;
Modifies model properties. The parameter is a dictionary containing the properties to be changed. Following properties can be changed: &#039;&#039;Name&#039;&#039;, &#039;&#039;Description&#039;&#039;, &#039;&#039;ProjectId&#039;&#039;, and &#039;&#039;Configuration&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The function returns the updated model object. Requires the &#039;&#039;GenericWrite&#039;&#039; permission for the project and the global &#039;&#039;CreateModel&#039;&#039; permission.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ModelById(1)&lt;br /&gt;
	.Modify(#{&lt;br /&gt;
		&amp;quot;Name&amp;quot;: &amp;quot;My model&amp;quot;,&lt;br /&gt;
		&amp;quot;Description&amp;quot;: &amp;quot;My description&amp;quot;,&lt;br /&gt;
		&amp;quot;ProjectId&amp;quot;: 2,&lt;br /&gt;
		&amp;quot;Configuration&amp;quot;: #{&lt;br /&gt;
			&amp;quot;DataSource&amp;quot;: #{&lt;br /&gt;
				&amp;quot;Cases&amp;quot;: #{&lt;br /&gt;
					&amp;quot;DataSourceType&amp;quot;: &amp;quot;datatable&amp;quot;,&lt;br /&gt;
					&amp;quot;DataTableName&amp;quot;: &amp;quot;My cases datatable&amp;quot;,&lt;br /&gt;
					&amp;quot;Columns&amp;quot;: #{&lt;br /&gt;
						&amp;quot;CaseId&amp;quot;: &amp;quot;Case Name&amp;quot;&lt;br /&gt;
					}&lt;br /&gt;
				},&lt;br /&gt;
				&amp;quot;Events&amp;quot;: #{&lt;br /&gt;
					&amp;quot;DataSourceType&amp;quot;: &amp;quot;datatable&amp;quot;,&lt;br /&gt;
					&amp;quot;DataTableName&amp;quot;: &amp;quot;My events datatable&amp;quot;,&lt;br /&gt;
					&amp;quot;Columns&amp;quot;: #{&lt;br /&gt;
						&amp;quot;CaseId&amp;quot;: &amp;quot;Case Name&amp;quot;,&lt;br /&gt;
						&amp;quot;EventType&amp;quot;: &amp;quot;Event Type&amp;quot;,&lt;br /&gt;
						&amp;quot;Timestamp&amp;quot;: &amp;quot;Start Time&amp;quot;&lt;br /&gt;
					}&lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||ResetModelCache&lt;br /&gt;
||(none)&lt;br /&gt;
||&lt;br /&gt;
Synchronously clears all cached model data. For a Snowflake model, deletes all cache tables related to the model from Snowflake. For an in-memory model, drops the model from the memory and also drops all other model related caches from the memory. &lt;br /&gt;
|-&lt;br /&gt;
||ResetPreprocessings&lt;br /&gt;
||(none)&lt;br /&gt;
||&lt;br /&gt;
Removes all cached items related to the Model, e.g. preprocessings and calculation results. In practice, the Model is reset to a state where it was right after the model was loaded into memory.&lt;br /&gt;
|-&lt;br /&gt;
||Restore&lt;br /&gt;
||(none)&lt;br /&gt;
||Restores the Model from the recycle bin back to the original location.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;ToSqlDataFrame&amp;quot;&amp;gt;ToSqlDataFrame&amp;lt;/span&amp;gt;&lt;br /&gt;
||In-memory dataframe&lt;br /&gt;
||Converts an in-memory dataframe to an SQL dataframe. In practice, an SQL query is created from the in-memory dataframe and the query is executed in the datasource so that the data is available in the datasource for further SQL operations. This function is intended only to small amounts of data which is less than 16384 rows.&lt;br /&gt;
&lt;br /&gt;
Example: Select matching cases from events data using in-memory dataframe:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
let model = ModelById(1);&lt;br /&gt;
let dfEvents = model.EventsDatatable.SqlDataFrame;&lt;br /&gt;
let inMemoryDf = ToDataFrame(&lt;br /&gt;
  [[&amp;quot;1&amp;quot;], [&amp;quot;2&amp;quot;], [&amp;quot;3&amp;quot;]],&lt;br /&gt;
  [#{&amp;quot;Name&amp;quot;: &amp;quot;id&amp;quot;, &amp;quot;DataType&amp;quot;: &amp;quot;String&amp;quot;}]&lt;br /&gt;
);&lt;br /&gt;
model.ToSqlDataFrame(inMemoryDf)&lt;br /&gt;
  .Join(dfEvents, [&amp;quot;id&amp;quot;: &amp;quot;CaseId&amp;quot;])&lt;br /&gt;
  .SelectDistinct([&amp;quot;CaseId&amp;quot;])&lt;br /&gt;
  .Collect();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;TriggerNotifications&amp;quot;&amp;gt;TriggerNotifications&amp;lt;/span&amp;gt; (Boolean)&lt;br /&gt;
||Notification names (String*)&lt;br /&gt;
||Triggers the given notifications for the Model. Notifications are given by their names. Triggering means that the configured rules are run and notification emails are sent as defined by the rules. If the notification names parameter is not provided, all notifications in the Model are triggered.&lt;br /&gt;
&lt;br /&gt;
The function return &#039;&#039;true&#039;&#039; if any notification were triggered, otherwise &#039;&#039;false&#039;&#039;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ModelById(123).TriggerNotifications([&amp;quot;Notification 1&amp;quot;, &amp;quot;Notification 2&amp;quot;]);&lt;br /&gt;
Triggers notifications Notification 1 and Notification 2 in model id 123.&lt;br /&gt;
&lt;br /&gt;
ModelById(123).TriggerNotifications();&lt;br /&gt;
Triggers all notifications in model id 123.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;CheckModelValidity&amp;quot;&amp;gt;CheckModelValidity&amp;lt;/span&amp;gt; (Object array)&lt;br /&gt;
||CheckData field in dictionary&lt;br /&gt;
||Checks the model validity and returns found issues. The returned data is an array of objects where each object represents one validity error and contains the following properties:&lt;br /&gt;
* &#039;&#039;&#039;IssueType&#039;&#039;&#039; (String): Specifies the issue type.&lt;br /&gt;
* &#039;&#039;&#039;ContextType&#039;&#039;&#039; (String): Context in which the issue was found, and it can be &#039;&#039;&#039;EventDataSource&#039;&#039;&#039;, &#039;&#039;&#039;CaseDataSource&#039;&#039;&#039;, &#039;&#039;&#039;OcelDataSource&#039;&#039;&#039;.&lt;br /&gt;
* &#039;&#039;&#039;Details&#039;&#039;&#039; (Dictionary): Additional details which depend on the type of the issue.&lt;br /&gt;
&lt;br /&gt;
There are two types of checks available (based on whether the &#039;&#039;&#039;CheckData&#039;&#039;&#039; parameter is defined):&lt;br /&gt;
* &#039;&#039;Lightweight check&#039;&#039;: The check is based on only the configuration data stored in QPR ProcessAnalyzer. This check is very quick and does not require running queries in datasource (e.g., in Snowflake).&lt;br /&gt;
* &#039;&#039;Full check&#039;&#039;: The check is comprehensive and it&#039;s able to detect any validity issues the model may have. The full check requires running queries to the actual data which makes the check slower, and in case of Snowflake, it uses the Snowflake warehouse to run the queries.&lt;br /&gt;
&lt;br /&gt;
The lightweight check is performed automatically by the [[QPR_ProcessAnalyzer_Project_Workspace|Workspace]], so if there are any validity issues that the lightweight check can detect, the Workspace notifies about them immediately. If there are any problems with the model calculation results, it might be a good idea to run the full validity check to confirm whether the problems are due to the model being invalid.&lt;br /&gt;
&lt;br /&gt;
Example: Lightweight check:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ToJson(ModelById(1).CheckModelValidity())&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Full check:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ToJson(ModelById(1).CheckModelValidity(#{ &amp;quot;CheckData&amp;quot;: true }))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||CortexAgentsQuery&lt;br /&gt;
||&lt;br /&gt;
||Creates a Snowflake Cortex semantic model (see &#039;&#039;GetSemanticModel&#039;&#039; function) for the process mining model and makes a natural language query on it using Snowflake Cortex Agents. More information: https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-agents. &lt;br /&gt;
&lt;br /&gt;
There are the following parameters:&lt;br /&gt;
# &#039;&#039;&#039;Parameters&#039;&#039;&#039;: Dictionary parameters given to the Cortex Agents REST API query (https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-agents-rest-api). There is a special handling for the following parameters:&lt;br /&gt;
#* &#039;&#039;&#039;model&#039;&#039;&#039;: If not defined, uses the default Cortex Agents model name configured into the database, or if that is not defined, uses &amp;quot;llama3.1-70b&amp;quot;.&lt;br /&gt;
#* &#039;&#039;&#039;_tools&#039;&#039;&#039;: Additional tool_spec of type &amp;quot;cortex_analyst_text_to_sql&amp;quot; will be added to this value with a reference to the generated semantic model.&lt;br /&gt;
#* &#039;&#039;&#039;_tool_resources&#039;&#039;&#039;: Generated semantic model is added as an additional resource.&lt;br /&gt;
# &#039;&#039;&#039;Filter configuration&#039;&#039;&#039;: Can be a string containing filter JSON or a dictionary containing the filter configuration. The semantic model is created for the filtered eventlog. If not defined, the entire model eventlog will be used.&lt;br /&gt;
# &#039;&#039;&#039;Event column role nappings&#039;&#039;&#039;: Mappings to apply for event columns. If not defined, default column mappings are used.&lt;br /&gt;
# &#039;&#039;&#039;Case column role mappings&#039;&#039;&#039;: Mappings to apply for case columns. If not defined, default column mappings are used.&lt;br /&gt;
&lt;br /&gt;
The function returns a dictionary with the following keys:&lt;br /&gt;
# &#039;&#039;&#039;Response&#039;&#039;&#039;: Actual response as a dictionary returned by the Cortex Agents.&lt;br /&gt;
# &#039;&#039;&#039;Response items&#039;&#039;&#039;: Contains processed response consisting of an array of objects having the following properties:&lt;br /&gt;
#* &#039;&#039;&#039;Text&#039;&#039;&#039;: Textual response.&lt;br /&gt;
#* &#039;&#039;&#039;Sql&#039;&#039;&#039;: Response SQL query string. Not mandatory.&lt;br /&gt;
#* &#039;&#039;&#039;SqlDataFrame&#039;&#039;&#039;: SqlDataFrame created for the SQL query in the Sql property. Only present if Sql is present.&lt;br /&gt;
|-&lt;br /&gt;
||GetSemanticModel&lt;br /&gt;
||&lt;br /&gt;
||Creates a Snowflake Cortex Analyst semantic model for the process mining model and returns it as a dictionary. More information: https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-analyst/semantic-model-spec.&lt;br /&gt;
&lt;br /&gt;
There are the following parameters:&lt;br /&gt;
# &#039;&#039;&#039;Filter configuration&#039;&#039;&#039;: Can be a string containing filter JSON or a dictionary containing the filter. The semantic model is created for the filtered eventlog. If not defined, the entire model eventlog will be used.&lt;br /&gt;
# &#039;&#039;&#039;Event column role mappings&#039;&#039;&#039;: Mappings to apply for event columns. If not defined, default column mappings are used.&lt;br /&gt;
# &#039;&#039;&#039;Case column role mappings&#039;&#039;&#039;: Mappings to apply for case columns. If not defined, default column mappings are used.&lt;br /&gt;
&lt;br /&gt;
Examples: Returns a semantic model without any filtering applied.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ModelById(1).GetSemanticModel();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Function to get Model by model id:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!&#039;&#039;&#039;Functions&#039;&#039;&#039;&lt;br /&gt;
!&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||ModelById&lt;br /&gt;
||&lt;br /&gt;
* Model id (Integer)&lt;br /&gt;
||&lt;br /&gt;
Returns [[QPR_ProcessAnalyzer_Objects_in_Expression_Language#Model|Model]] object corresponding to the provided model id.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Object-centric model==&lt;br /&gt;
Object-centric models additionally have the following properties and functions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!&#039;&#039;&#039;Object-Centric model properties&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||IsOcelModel (boolean)&lt;br /&gt;
||Returns &#039;&#039;true&#039;&#039; when the model is an OCEL model.&lt;br /&gt;
|-&lt;br /&gt;
||OcelEvents (Datatable)&lt;br /&gt;
||Datatable containing event data for the OCEL model. Value &#039;&#039;null&#039;&#039; is returned if event datatable has not been configured for the model. Throws an unsupported operation exception if the model is not an OCEL model.&lt;br /&gt;
|-&lt;br /&gt;
||OcelEventToObject (Datatable)&lt;br /&gt;
||Datatable containing event-to-object relations data for the OCEL model. Value &#039;&#039;null&#039;&#039; is returned if event-to-object relation datatable has not been configured for the model. Throws an unsupported operation exception if the model is not an OCEL model.&lt;br /&gt;
|-&lt;br /&gt;
||OcelEventTypes (Dictionary)&lt;br /&gt;
||Returns a dictionary containing event type names as keys and the datatables holding event data for that event type in this OCEL model as value. An empty array is returned if event types datatable has not been configured for the model. Throws an unsupported operation exception if the model is not an OCEL model.&lt;br /&gt;
&lt;br /&gt;
Example: Get datatable for &amp;quot;Create order&amp;quot; events:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ModelById(1).OcelEventTypes.Get(&amp;quot;Create order&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||OcelObjects (Datatable)&lt;br /&gt;
||Datatable containing objects data for the OCEL model. Value &#039;&#039;null&#039;&#039; is returned if object datatable has not been configured for the model. Throws an unsupported operation exception if the model is not an OCEL model.&lt;br /&gt;
|-&lt;br /&gt;
||OcelObjectToObject (Datatable)&lt;br /&gt;
||Datatable containing object-to-object relations data for the OCEL model. Value &#039;&#039;null&#039;&#039; is returned if object-to-object relation datatable has not been configured for the model. Throws an unsupported operation exception if the model is not an OCEL model.&lt;br /&gt;
|-&lt;br /&gt;
||OcelObjectTypes (Dictionary)&lt;br /&gt;
||Returns a dictionary containing object type names as keys and the datatables holding data for that object type in this OCEL model as value. An empty array is returned if object types have not been configured for this model. Throws an unsupported operation exception if the model is not an OCEL model.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!&#039;&#039;&#039;Object-centric model functions&#039;&#039;&#039;&lt;br /&gt;
!&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||OcelEventType&lt;br /&gt;
||Event type name (String)&lt;br /&gt;
||&lt;br /&gt;
Datatable containing event type attributes of given event type in this OCEL model. Value &#039;&#039;null&#039;&#039; is returned if a datatable is not configured for this model for given event type. Throws an unsupported operation exception if the model is not an OCEL model.&lt;br /&gt;
&lt;br /&gt;
Example: Get datatable for &amp;quot;Create order&amp;quot; events:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ModelById(1).OcelEventType(&amp;quot;Create order&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||OcelObjectType&lt;br /&gt;
||Object type name (String)&lt;br /&gt;
||Datatable containing object type attributes of given object type in this OCEL model. Value &#039;&#039;null&#039;&#039; is returned if a datatable is not configured for this model for given object type. Throws an unsupported operation exception if the model is not an OCEL model.&lt;br /&gt;
|-&lt;br /&gt;
||OcelObjectTypeConfiguration&lt;br /&gt;
||Object type name (String)&lt;br /&gt;
||Returns a matching configuration object with the following properties:&amp;lt;br&amp;gt;&lt;br /&gt;
# Datatable: name of the datatable&lt;br /&gt;
# Unit: unit label for object type items&lt;br /&gt;
&#039;&#039;Null&#039;&#039; is returned if the given object type is not found in the model configuration.  &lt;br /&gt;
If the object type name is not specified or &#039;&#039;null&#039;&#039;, the function returns a dictionary containing configurations for all defined object types.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Project ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!&#039;&#039;&#039;Project properties&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||CreatedBy (User)&lt;br /&gt;
||User who created the Project.&lt;br /&gt;
|-&lt;br /&gt;
||CreatedDate (DateTime)&lt;br /&gt;
||Timestamp when the Project was created.&lt;br /&gt;
|-&lt;br /&gt;
||Configuration (Dictionary)&lt;br /&gt;
||Project settings as Dictionary object. See example in &#039;&#039;ConfigurationJson&#039;&#039; property.&lt;br /&gt;
|-&lt;br /&gt;
||ConfigurationJson (String)&lt;br /&gt;
||Project settings as json string.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;DefaultLocationInDataSource&amp;quot;: {&lt;br /&gt;
    &amp;quot;Database&amp;quot;: &amp;quot;MyDatabase&amp;quot;,&lt;br /&gt;
    &amp;quot;Schema&amp;quot;: &amp;quot;MySchema&amp;quot;&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;ConnectionStringKeys&amp;quot;: {&lt;br /&gt;
    &amp;quot;Snowflake&amp;quot;: &amp;quot;MyKey1&amp;quot;,&lt;br /&gt;
    &amp;quot;SqlServer&amp;quot;: &amp;quot;MyKey2&amp;quot;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||Dashboards (Dashboard*)&lt;br /&gt;
||Returns all [[Dashboard_in_Expression_Language|dashboards]] in the project.&lt;br /&gt;
|-&lt;br /&gt;
||Datatables (Datatable*)&lt;br /&gt;
||Returns all Datatables in the project.&lt;br /&gt;
|-&lt;br /&gt;
||DeletedDate (DateTime)&lt;br /&gt;
||Timestamp when the Project was deleted (moved to the recycle bin).&lt;br /&gt;
|-&lt;br /&gt;
||Description (String)&lt;br /&gt;
||Project description. The project description may contain line breaks.&lt;br /&gt;
|-&lt;br /&gt;
||DeletedBy (User)&lt;br /&gt;
||User who deleted the Project (moved to the recycle bin).&lt;br /&gt;
|-&lt;br /&gt;
||Id (Integer)&lt;br /&gt;
||Id of the Project.&lt;br /&gt;
|-&lt;br /&gt;
||LastModifiedBy (User)&lt;br /&gt;
||User who last modified the Project.&lt;br /&gt;
|-&lt;br /&gt;
||LastModifiedDate (DateTime)&lt;br /&gt;
||Timestamp when the Project was last modified (refers to the project name, description and parent, not the contents of the project).&lt;br /&gt;
|-&lt;br /&gt;
||Name (String)&lt;br /&gt;
||Name of the Project.&lt;br /&gt;
|-&lt;br /&gt;
||Models (Model*)&lt;br /&gt;
||Models that are in the Project.&lt;br /&gt;
|-&lt;br /&gt;
||Parent (Project)&lt;br /&gt;
||Parent project, i.e. a Project where the Project is located in the hierarchy of Projects. Returns &#039;&#039;null&#039;&#039; for root level Projects. Throws an error if user doesn&#039;t have access to the parent project.&lt;br /&gt;
|-&lt;br /&gt;
||ParentProjectId (Integer)&lt;br /&gt;
||Parent project id. Returns &#039;&#039;null&#039;&#039; for root level Projects. The parent project id is returned even if user doesn&#039;t have access to the parent project.&lt;br /&gt;
|-&lt;br /&gt;
||Scripts (Script*)&lt;br /&gt;
||Scripts that are in the Project.&lt;br /&gt;
|-&lt;br /&gt;
||Secrets (Dictionary*)&lt;br /&gt;
||Returns array of all [[Storing_Secrets_for_Scripts|secrets]] in the project as Dictionary with following properties:&lt;br /&gt;
* &#039;&#039;&#039;Name&#039;&#039;&#039; (string): Name of the secret.&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039; (string): Type of the secret which is one of the following: &amp;quot;odbc&amp;quot;, &amp;quot;sap&amp;quot;, &amp;quot;salesforce&amp;quot;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!&#039;&#039;&#039;Project functions&#039;&#039;&#039;&lt;br /&gt;
!&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||CreateDashboard (Dashboard)&lt;br /&gt;
||Parameters dictionary&lt;br /&gt;
||Creates a dashboard to the project. &#039;&#039;EditDashboards&#039;&#039; permission to the project is required. The parameter is dictionary with following supported dashboard properties:&lt;br /&gt;
* &#039;&#039;&#039;Name&#039;&#039;&#039; (String): Name of the dashboard.&lt;br /&gt;
* &#039;&#039;&#039;Identifier&#039;&#039;&#039; (String): Identifier of the dashboard.&lt;br /&gt;
* &#039;&#039;&#039;Description&#039;&#039;&#039; (String): Description of the dashboard.&lt;br /&gt;
* &#039;&#039;&#039;Content&#039;&#039;&#039; (Dictionary): Content of the dashboard.&lt;br /&gt;
&lt;br /&gt;
Example: Create empty dashboard.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProjectById(1)&lt;br /&gt;
  .CreateDashboard(#{&lt;br /&gt;
    &amp;quot;Name&amp;quot;: &amp;quot;My dashboard&amp;quot;,&lt;br /&gt;
    &amp;quot;Identifier&amp;quot;: &amp;quot;MyDashboard&amp;quot;&lt;br /&gt;
  });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Create dashboard with a chart.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProjectById(1)&lt;br /&gt;
  .CreateDashboard(#{&lt;br /&gt;
    &amp;quot;Name&amp;quot;: &amp;quot;My dashboard&amp;quot;,&lt;br /&gt;
    &amp;quot;Content&amp;quot;: #{&lt;br /&gt;
      &amp;quot;version&amp;quot;: 4,&lt;br /&gt;
      &amp;quot;typeName&amp;quot;: &amp;quot;View&amp;quot;,&lt;br /&gt;
      &amp;quot;name&amp;quot;: &amp;quot;My dashboard&amp;quot;,&lt;br /&gt;
      &amp;quot;subElements&amp;quot;: [&lt;br /&gt;
        #{&lt;br /&gt;
          &amp;quot;position&amp;quot;: #{&lt;br /&gt;
            &amp;quot;x&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;y&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;width&amp;quot;: 0.5,&lt;br /&gt;
            &amp;quot;height&amp;quot;: 0.5,&lt;br /&gt;
            &amp;quot;zOrder&amp;quot;: 0&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;element&amp;quot;: #{&lt;br /&gt;
            &amp;quot;typeName&amp;quot;: &amp;quot;Chart&amp;quot;,&lt;br /&gt;
            &amp;quot;configuration&amp;quot;: #{&lt;br /&gt;
              &amp;quot;root&amp;quot;: #{&lt;br /&gt;
                &amp;quot;expressionType&amp;quot;: &amp;quot;Cases&amp;quot;,&lt;br /&gt;
                &amp;quot;expressionParameters&amp;quot;: #{}&lt;br /&gt;
              },&lt;br /&gt;
              &amp;quot;measures&amp;quot;: [#{&lt;br /&gt;
                &amp;quot;expressionType&amp;quot;: &amp;quot;Count&amp;quot;,&lt;br /&gt;
                &amp;quot;expressionParameters&amp;quot;: #{}&lt;br /&gt;
              }]&lt;br /&gt;
            }&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      ]&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;CreateDatatable&amp;quot;&amp;gt;CreateDatatable&amp;lt;/span&amp;gt; (Datatable)&lt;br /&gt;
||&lt;br /&gt;
* Parameters dictionary&lt;br /&gt;
||Creates datatable to the project. After creation, there are no columns or rows in the datatable. The function returns the created datatable entity. Following properties can be set for the datatable:&lt;br /&gt;
* &#039;&#039;&#039;Name&#039;&#039;&#039; (string): Name of the datatable. This parameter is mandatory.&lt;br /&gt;
* &#039;&#039;&#039;Description&#039;&#039;&#039; (string): Description for the datatable. This parameter is optional.&lt;br /&gt;
* &#039;&#039;&#039;NameInDataSource&#039;&#039;&#039; (string): Table name in the datasource (e.g., in Snowflake) which this datatable is linked to. This parameter is optional.&lt;br /&gt;
* &#039;&#039;&#039;SchemaNameInDataSource&#039;&#039;&#039; (string): Schema name in the datasource (e.g., in Snowflake) which this datatable is linked to. This parameter is optional.&lt;br /&gt;
* &#039;&#039;&#039;DatabaseNameInDataSource&#039;&#039;&#039; (string): Database name in the datasource (e.g., in Snowflake) which this datatable is linked to. This parameter is optional.&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039; (string): Defines where the data for the datatable is located. Available values are &#039;&#039;&#039;Snowflake&#039;&#039;&#039;, &#039;&#039;&#039;SqlServer&#039;&#039;&#039;, and &#039;&#039;&#039;Local&#039;&#039;&#039;.  This parameter is optional and default value is defined by the [[PA_Configuration_database_table#General_Settings|DefaultDataSource]] setting.&lt;br /&gt;
* &#039;&#039;&#039;Connection&#039;&#039;&#039;: Connection object for the datatable. This parameter is optional.&lt;br /&gt;
&lt;br /&gt;
Example: Create a new datatable:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProjectById(1).CreateDatatable(#{&lt;br /&gt;
  &amp;quot;Name&amp;quot;: &amp;quot;My datatable&amp;quot;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Create Snowflake datatable linked to a custom table:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProjectById(1).CreateDatatable(#{&lt;br /&gt;
  &amp;quot;Name&amp;quot;: &amp;quot;My datatable&amp;quot;,&lt;br /&gt;
  &amp;quot;Description&amp;quot;: &amp;quot;My description&amp;quot;,&lt;br /&gt;
  &amp;quot;NameInDataSource&amp;quot;: &amp;quot;MyTable&amp;quot;,&lt;br /&gt;
  &amp;quot;SchemaNameInDataSource&amp;quot;: &amp;quot;MySchema&amp;quot;,&lt;br /&gt;
  &amp;quot;DatabaseNameInDataSource&amp;quot;: &amp;quot;MyDatabase&amp;quot;,&lt;br /&gt;
  &amp;quot;Type&amp;quot;: &amp;quot;Snowflake&amp;quot;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Create Snowflake datatable where connection string is stored as a [[Storing_Secrets_for_Scripts|secret]]:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProjectById(1).CreateDatatable(#{&lt;br /&gt;
  &amp;quot;Name&amp;quot;: &amp;quot;My datatable&amp;quot;,&lt;br /&gt;
  &amp;quot;Type&amp;quot;: &amp;quot;Snowflake&amp;quot;,&lt;br /&gt;
  &amp;quot;Connection&amp;quot;: ProjectById(1).CreateSnowflakeConnection(#{ &amp;quot;OdbcConnectionStringKey&amp;quot;: &amp;quot;MyKey&amp;quot; })&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||CreateMeaConnection&lt;br /&gt;
||&lt;br /&gt;
||&lt;br /&gt;
Creates an object representing connection to QPR MEA (QPR Suite) Web Service. The function parameter is a dictionary containing the property &#039;&#039;&#039;ConnectionStringKey&#039;&#039;&#039; which defines the MEA connection string secret name in the same project. When the connection object has been created, MEA Web Service [[QPR_MEA_Integration|queries and other operations]] can be executed using it.&lt;br /&gt;
&lt;br /&gt;
Example: create connection:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
let connection = ProjectByName(&amp;quot;MyProject&amp;quot;).CreateMeaConnection( #{&amp;quot;ConnectionStringKey&amp;quot;: &amp;quot;MyMeaConnection&amp;quot;} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: use connection:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
let results = connection.QueryObjects(&amp;quot;[PG.785401983.683494101]&amp;quot;, &amp;quot;name, typename&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||CreateModel (Model)&lt;br /&gt;
||&lt;br /&gt;
* Parameters dictionary&lt;br /&gt;
||Creates a model to a project. Requires &#039;&#039;GenericWrite&#039;&#039; permission for the Project and global &#039;&#039;CreateModel&#039;&#039; permission. If a model with that name already exists, an exception is thrown.&lt;br /&gt;
&lt;br /&gt;
Parameters dictionary has the following properties:&lt;br /&gt;
* &#039;&#039;&#039;Name&#039;&#039;&#039;: Name of the model. This property is mandatory.&lt;br /&gt;
* &#039;&#039;&#039;Description&#039;&#039;&#039;: Description of the model. This property is optional.&lt;br /&gt;
* &#039;&#039;&#039;Configuration&#039;&#039;&#039;: Configuration dictionary for the model. This property is technically optional, but a working model requires at least datasource settings to be defined.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProjectById(1).CreateModel(#{    &lt;br /&gt;
  &amp;quot;Name&amp;quot;: &amp;quot;My model&amp;quot;,&lt;br /&gt;
  &amp;quot;Description&amp;quot;: &amp;quot;My description&amp;quot;,&lt;br /&gt;
  &amp;quot;Configuration&amp;quot;: #{&lt;br /&gt;
    &amp;quot;DataSource&amp;quot;: #{&lt;br /&gt;
      &amp;quot;Cases&amp;quot;: #{&lt;br /&gt;
        &amp;quot;DataSourceType&amp;quot;: &amp;quot;datatable&amp;quot;,&lt;br /&gt;
        &amp;quot;DataTableName&amp;quot;: &amp;quot;My cases datatable&amp;quot;,&lt;br /&gt;
        &amp;quot;Columns&amp;quot;: #{&lt;br /&gt;
          &amp;quot;CaseId&amp;quot;: &amp;quot;Case Name&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;Events&amp;quot;: #{&lt;br /&gt;
        &amp;quot;DataSourceType&amp;quot;: &amp;quot;datatable&amp;quot;,&lt;br /&gt;
        &amp;quot;DataTableName&amp;quot;: &amp;quot;My events datatable&amp;quot;,&lt;br /&gt;
        &amp;quot;Columns&amp;quot;: #{&lt;br /&gt;
           &amp;quot;CaseId&amp;quot;: &amp;quot;Case Name&amp;quot;,&lt;br /&gt;
           &amp;quot;EventType&amp;quot;: &amp;quot;Event Type&amp;quot;,&lt;br /&gt;
           &amp;quot;Timestamp&amp;quot;: &amp;quot;Start Time&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;CreateProject&amp;quot;&amp;gt;CreateProject&amp;lt;/span&amp;gt; (Project)&lt;br /&gt;
||&lt;br /&gt;
* Parameters dictionary&lt;br /&gt;
||Create a project as a sub-project of the context project. Returns the created project. Requires the &#039;&#039;ManageProject&#039;&#039; permission.&lt;br /&gt;
&lt;br /&gt;
Parameters dictionary has the following properties:&lt;br /&gt;
* &#039;&#039;&#039;Name&#039;&#039;&#039; (string): Name of the project. This property is required.&lt;br /&gt;
* &#039;&#039;&#039;Description&#039;&#039;&#039; (string): Description of the project.&lt;br /&gt;
* &#039;&#039;&#039;ParentProjectId&#039;&#039;&#039; (integer): Id of the parent project where the new project is created. This parameter is usually not needed because the parent project is the context project. The CreateProject function is also available in the generic context where the &#039;&#039;ParentProjectId&#039;&#039; parameter is needed to create sub-projects.&lt;br /&gt;
* &#039;&#039;&#039;DatabaseNameInDataSource&#039;&#039;&#039; (string): Snowflake database the project is linked to. Data for the datatables in this project will be located in this database.&lt;br /&gt;
* &#039;&#039;&#039;SchemaNameInDataSource&#039;&#039;&#039; (string): Snowflake schema the project is linked to. Data for the datatables in this project will be located in this schema. If the schema is defined, also the &#039;&#039;DatabaseNameInDataSource&#039;&#039; needs to be defined.&lt;br /&gt;
* &#039;&#039;&#039;SnowflakeConnectionStringKey&#039;&#039;&#039; (string): Snowflake connection string key to be used for the datatables in this project. &lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProjectById(1).CreateProject(#{&lt;br /&gt;
  &amp;quot;Name&amp;quot;: &amp;quot;My project&amp;quot;, &lt;br /&gt;
  &amp;quot;Description&amp;quot;: &amp;quot;My description&amp;quot;, &lt;br /&gt;
  &amp;quot;DatabaseNameInDataSource&amp;quot;: &amp;quot;My database&amp;quot;, &lt;br /&gt;
  &amp;quot;SchemaNameInDataSource&amp;quot;: &amp;quot;My schema&amp;quot; &lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||DatatableByName (Datatable)&lt;br /&gt;
||Datatable name (String)&lt;br /&gt;
||&lt;br /&gt;
Returns Datatable by its name located in the project. Returns null, if Datatable with that name does not exist in the project.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProjectById(123).DatatableByName(&amp;quot;MyDatatable1&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Get datatable by name, and create it if it doesn&#039;t exist:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
let project = ProjectById(123);&lt;br /&gt;
let datatableName = &amp;quot;MyDatatable1&amp;quot;;&lt;br /&gt;
let datatable = project.DatatableByName(datatableName);&lt;br /&gt;
if (datatable == null) {&lt;br /&gt;
  datatable = project.CreateDatatable(datatableName);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||DeletePermanently&lt;br /&gt;
||(none)&lt;br /&gt;
||Deletes the Project permanently. Note that the Project doesn&#039;t need to be in the recycle bin to be able to delete it permanently.&lt;br /&gt;
|-&lt;br /&gt;
||Export (String)&lt;br /&gt;
||(none)&lt;br /&gt;
||Exports the project and its content to a json string. The json format is described in [[Projects Export File Format]].&lt;br /&gt;
&lt;br /&gt;
Example: Export project id 1 to json data:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProjectById(1).Export();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||Import&lt;br /&gt;
||JSON string&lt;br /&gt;
||Creates one or several projects from a json string. The project(s) are created as child projects of the context project. The json format is described in [[Projects Export File Format]]. The function returns the created project objects. In case the project names already exist, the import operation automatically adjusts the names to be unique.&lt;br /&gt;
&lt;br /&gt;
Example: Create project from json data (as child of project id 1):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
let jsonData = `{ &amp;quot;Projects&amp;quot;: [ { &amp;quot;Name&amp;quot;: &amp;quot;My project&amp;quot; } ] }`;&lt;br /&gt;
let result = ProjectById(1).Import(jsonData);&lt;br /&gt;
let createdProjectId = result[&amp;quot;Projects&amp;quot;][0].Id;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||Restore&lt;br /&gt;
||(none)&lt;br /&gt;
||Restores the Project from the recycle bin back to the original location.&lt;br /&gt;
|-&lt;br /&gt;
||ModelByName (Model)&lt;br /&gt;
||Model name (String)&lt;br /&gt;
||&lt;br /&gt;
Returns Model by its name located in the project. Returns null, if Model with that name does not exist in the project.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProjectById(123).ModelByName(&amp;quot;My Model 1&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;ModifyProject&amp;quot;&amp;gt;Modify&amp;lt;/span&amp;gt; (Project)&lt;br /&gt;
||Dictionary of settings to change&lt;br /&gt;
||&lt;br /&gt;
Change project settings. Following settings are supported:&lt;br /&gt;
* &#039;&#039;&#039;Name&#039;&#039;&#039; (String): Name of the project.&lt;br /&gt;
* &#039;&#039;&#039;Description&#039;&#039;&#039; (String): Description text of the project.&lt;br /&gt;
* &#039;&#039;&#039;ParentProjectId&#039;&#039;&#039; (Integer): Parent project id. Changing this effectively moves the project into different parent project.&lt;br /&gt;
* &#039;&#039;&#039;DatabaseNameInDataSource&#039;&#039;&#039;: Name of the Snowflake database where the project&#039;s datatables are located. The database needs to exist in the same Snowflake account configured in the Snowflake connection string. When defining this setting, define also the &#039;&#039;SchemaNameInDataSource&#039;&#039;.&lt;br /&gt;
* &#039;&#039;&#039;SchemaNameInDataSource&#039;&#039;&#039;: Name of the Snowflake schema where the project&#039;s datatables are located. The schema needs to exist in the same Snowflake account configured in the Snowflake connection string. When defining this setting, define also the &#039;&#039;DatabaseNameInDataSource&#039;&#039;.&lt;br /&gt;
* &#039;&#039;&#039;SnowflakeConnectionStringKey&#039;&#039;&#039; (String): Snowflake connection string key for the project. Snowflake datatables in the project will use connection string behind this key (unless specified by the datatatable).&lt;br /&gt;
* &#039;&#039;&#039;SqlServerConnectionStringKey&#039;&#039;&#039; (String): SQL Server connection string key. SQL Server datatables in the project will use connection string behind this key (unless specified by the datatatable).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;ManageProject&#039;&#039; permission is needed to change project properties.&lt;br /&gt;
&lt;br /&gt;
Example: Change project name and move project into other parent project:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProjectById(1)&lt;br /&gt;
  .Modify(#{&lt;br /&gt;
    &amp;quot;Name&amp;quot;: &amp;quot;Project 1&amp;quot;&lt;br /&gt;
    &amp;quot;ParentProjectId&amp;quot;: 2&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Set Snowflake connection string key for the project:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProjectById(1)&lt;br /&gt;
  .Modify(#{&lt;br /&gt;
    &amp;quot;SnowflakeConnectionStringKey&amp;quot;: &amp;quot;MyKey1&amp;quot;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||ScriptByName (Script)&lt;br /&gt;
||Script name (String)&lt;br /&gt;
||&lt;br /&gt;
Returns Script by its name located in the project. Returns null, if Script with that name does not exist in the project.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProjectById(123).ScriptByName(&amp;quot;MyScript1&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;SetSecret&amp;quot;&amp;gt;SetSecret&amp;lt;/span&amp;gt;&lt;br /&gt;
||&lt;br /&gt;
# Secret type (string)&lt;br /&gt;
# Secret name (string)&lt;br /&gt;
# Secret value (string)&lt;br /&gt;
||Sets or adds a [[Storing_Secrets_for_Scripts|secret]] for the project. Setting the secret value to &#039;&#039;null&#039;&#039; removes the secret. There can be several secrets with the same name in the same project if the type of the secret is different. Setting secrets requires the project specific &#039;&#039;ManageProject&#039;&#039; permission.&lt;br /&gt;
&lt;br /&gt;
Parameters:&lt;br /&gt;
# &#039;&#039;&#039;Type&#039;&#039;&#039; (string): Secret type which is one of the following:&lt;br /&gt;
#* &amp;quot;externaldatatableconnection&amp;quot;: Snowflake ODBC connection string for datatables.&lt;br /&gt;
#* &amp;quot;odbc&amp;quot;: ODBC connection string (e.g., to extract data in scripts, or load an in-memory model).&lt;br /&gt;
#* &amp;quot;oledb&amp;quot;: OleDB connection string (e.g., to extract data in scripts, or load an in-memory model).&lt;br /&gt;
#* &amp;quot;sap&amp;quot;: SAP password.&lt;br /&gt;
#* &amp;quot;salesforce&amp;quot;: Salesforce password.&lt;br /&gt;
#* &amp;quot;sql&amp;quot;: SQL Server connection string.&lt;br /&gt;
#* &amp;quot;qprmea&amp;quot;: QPR MEA connection string.&lt;br /&gt;
# &#039;&#039;&#039;Name&#039;&#039;&#039; (string): Secret name, used to refer to the secret in the commands.&lt;br /&gt;
# &#039;&#039;&#039;Value&#039;&#039;&#039; (string): Secret value which contains the confidential information.&lt;br /&gt;
&lt;br /&gt;
Example: Set SAP password:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProjectById(1).SetSecret(&amp;quot;sap&amp;quot;, &amp;quot;MySapPassword&amp;quot;, &amp;quot;I l0ve 5AP!&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Remove SAP password:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProjectById(1).SetSecret(&amp;quot;sap&amp;quot;, &amp;quot;MySapPassword&amp;quot;, null);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Functions to get project:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!&#039;&#039;&#039;Functions&#039;&#039;&#039;&lt;br /&gt;
!&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||ProjectById&lt;br /&gt;
||Project id (Integer)&lt;br /&gt;
||&lt;br /&gt;
Returns project object corresponding to the provided project id.&lt;br /&gt;
|-&lt;br /&gt;
||ProjectByName&lt;br /&gt;
||Project name (String)&lt;br /&gt;
||&lt;br /&gt;
Returns project object by given project name. If there is no such project or user doesn&#039;t have access to it, &#039;&#039;null&#039;&#039; value is returned. If there are multiple projects with the same name, one of them is returned.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
let project = ProjectByName(&amp;quot;My Project&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Functions to create project:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!&#039;&#039;&#039;Functions&#039;&#039;&#039;&lt;br /&gt;
!&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;CreateProject&amp;quot;&amp;gt;CreateProject&amp;lt;/span&amp;gt; (Project)&lt;br /&gt;
||Parameters dictionary&lt;br /&gt;
||Create a project. This is a similar function as the [[QPR_ProcessAnalyzer_Objects_in_Expression_Language#CreateProject|CreateProject function]] in the project context. This function in the generic context is needed to create root-level projects (which don&#039;t have parent project).&lt;br /&gt;
&lt;br /&gt;
Example: create a root project:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CreateProject(#{&lt;br /&gt;
  &amp;quot;Name&amp;quot;: &amp;quot;My project&amp;quot;&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: create a sub-project:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CreateProject(#{&lt;br /&gt;
  &amp;quot;Name&amp;quot;: &amp;quot;My project&amp;quot;&lt;br /&gt;
  &amp;quot;ParentProjectId&amp;quot;: 1&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;Import&amp;quot;&amp;gt;Import&amp;lt;/span&amp;gt; (Project*)&lt;br /&gt;
||JSON string&lt;br /&gt;
||Creates one or several projects from a json string. The project(s) are created as the root level projects. The json format is described in [[Projects Export File Format]]. The function returns the created project objects. In case the project names already exist, the import operation automatically adjusts the names to be unique.&lt;br /&gt;
&lt;br /&gt;
Example: Create a root level project from json data:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
let jsonData = `{ &amp;quot;Projects&amp;quot;: [ { &amp;quot;Name&amp;quot;: &amp;quot;My project&amp;quot; } ] }`;&lt;br /&gt;
let result = Import(jsonData);&lt;br /&gt;
let createdProjectId = result[&amp;quot;Projects&amp;quot;][0].Id;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Script ==&lt;br /&gt;
Scripts are entities that contain executable code, that can be run. Usually scripts contains ETL routines but also other kind of tasks are possible.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!&#039;&#039;&#039;Script properties&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||Code (String)&lt;br /&gt;
||Script code.&lt;br /&gt;
|-&lt;br /&gt;
||Configuration (Dictionary)&lt;br /&gt;
||Script&#039;s configuration.&lt;br /&gt;
|-&lt;br /&gt;
||CreatedBy (User)&lt;br /&gt;
||User who created the Script.&lt;br /&gt;
|-&lt;br /&gt;
||CreatedDate (DateTime)&lt;br /&gt;
||Timestamp when the Script was created.&lt;br /&gt;
|-&lt;br /&gt;
||CurrentRunStart (DateTime)&lt;br /&gt;
||Timestamp of the current run start. Null if the script is currently not running.&lt;br /&gt;
|-&lt;br /&gt;
||Description (String)&lt;br /&gt;
||Description of the Script.&lt;br /&gt;
|-&lt;br /&gt;
||Id (Integer)&lt;br /&gt;
||Id of the Script.&lt;br /&gt;
|-&lt;br /&gt;
||Language (String)&lt;br /&gt;
||Either of the following scripting language: &#039;&#039;&#039;Expression&#039;&#039;&#039; or &#039;&#039;&#039;SQL&#039;&#039;&#039;. When language is Expression, the script is run as an expression script, and when language is SQL, the script is run as an SQL script (using the sandbox database).&lt;br /&gt;
|-&lt;br /&gt;
||LastModifiedBy (User)&lt;br /&gt;
||User who last modified the Script.&lt;br /&gt;
|-&lt;br /&gt;
||LastModifiedDate (DateTime)&lt;br /&gt;
||Timestamp when the Script was last modified.&lt;br /&gt;
|-&lt;br /&gt;
||LastRunEnd (DateTime)&lt;br /&gt;
||Timestamp of the last completed script run end (either successful completion or failure). Null if the Script hasn&#039;t been run yet.&lt;br /&gt;
|-&lt;br /&gt;
||LastRunResult (String)&lt;br /&gt;
||Result of the last run. Options are:&lt;br /&gt;
* &#039;&#039;&#039;Completed&#039;&#039;&#039;: The last run was completed successfully.&lt;br /&gt;
* &#039;&#039;&#039;Failed&#039;&#039;&#039;: An error occurred during the last run, so likely the script did not complete as intended.&lt;br /&gt;
* &#039;&#039;&#039;Aborted&#039;&#039;&#039;: Script run was manually stopped prematurely by a user, so the script did not proceeded in the end.&lt;br /&gt;
&lt;br /&gt;
Null if the Script hasn&#039;t been run yet.&lt;br /&gt;
|-&lt;br /&gt;
||LastRunStart (DateTime)&lt;br /&gt;
||Timestamp of the last completed script run start time. Null if the Script hasn&#039;t been run yet.&lt;br /&gt;
|-&lt;br /&gt;
||Name (String)&lt;br /&gt;
||Name of the Script.&lt;br /&gt;
|-&lt;br /&gt;
||OperationId (Integer)&lt;br /&gt;
||Id of the operation which runs the Script. Null if the script is currently not running.&lt;br /&gt;
|-&lt;br /&gt;
||Project (Project)&lt;br /&gt;
||Project where the Script is located. Null if the script is in the global context.&lt;br /&gt;
|-&lt;br /&gt;
||ProjectId (Integer)&lt;br /&gt;
||Id of the project where the Script is located. Null if the script is in the global context.&lt;br /&gt;
|-&lt;br /&gt;
||Status (String)&lt;br /&gt;
||Current status of the script. Options are:&lt;br /&gt;
* &#039;&#039;&#039;Ready&#039;&#039;&#039;: Script is not running. In this status, the script can be started (changing the status to &#039;&#039;Running&#039;&#039;).&lt;br /&gt;
* &#039;&#039;&#039;Running&#039;&#039;&#039;: Script is running. In this status, the script can be stopped (changing the status to &#039;&#039;Stopping&#039;&#039;). Calling stop just requests a script to stop, and the actual stopping occurs some time later.&lt;br /&gt;
* &#039;&#039;&#039;Stopping&#039;&#039;&#039;: Script has been requested to be stopped, but it&#039;s still running. In this status, neither start nor stop can be called for the script. When the script eventually stops, its status changes to &#039;&#039;Ready&#039;&#039;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!&#039;&#039;&#039;Script functions&#039;&#039;&#039;&lt;br /&gt;
!&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||Run (Object)&lt;br /&gt;
||Dictionary of parameters&lt;br /&gt;
||&lt;br /&gt;
Runs the script using the provided parameters. The parameters are available in the script as variables (see the example). Any type of variables can be passed to the script. Note that if the script assumes certain variables, but that they are not passed to the script, the script run will throw an error. &lt;br /&gt;
&lt;br /&gt;
For SQL scripts, the passed parameters are available in the script as variables in format &#039;&#039;&#039;@_parameter_&amp;lt;ParameterName&amp;gt;&#039;&#039;&#039; where &amp;lt;ParameterName&amp;gt; is the name of the parameter, e.g. &#039;&#039;parameter_myParameter1&#039;&#039;. Only string type of parameters can be used, so any other type of data in parameter values is converted into strings.&lt;br /&gt;
&lt;br /&gt;
The return value of the script is returned by the Run function. Expression scripts return a value with the &#039;&#039;return&#039;&#039; statement or alternatively the result of the last line of the script is the return value. If the script does not return any value, the Run function returns &#039;&#039;_empty&#039;&#039;. For SQL scripts, the return value is the last dataset produced by the script (returned as a DataFrame) (SQL scripts might create several datasets using the &#039;&#039;--#ShowReport&#039;&#039; command or the &#039;&#039;Show&#039;&#039; parameter).&lt;br /&gt;
&lt;br /&gt;
When a script is called using the Run function, the called script status does not change, because it&#039;s the parent script that is &#039;&#039;Running&#039;&#039;. Also the called script log is not filled, but instead the logging goes to the calling script.&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to call a script using the Run function several times simultaneously.&lt;br /&gt;
&lt;br /&gt;
If there is an error when running the called script, the Run function throws the error to the calling script.&lt;br /&gt;
&lt;br /&gt;
Scripts are run in the script entity context, so for example the following properties are available:&lt;br /&gt;
* Id: Script id&lt;br /&gt;
* Name: Script name&lt;br /&gt;
* Project.Id: Project id where the script is located&lt;br /&gt;
* Project.Name: Name of the project where the script is located&lt;br /&gt;
&lt;br /&gt;
Example: Following script (id 123) raises a specified number to a specified power:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
return Pow(numberToRaise, exponent);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The script can be called as follows (returning 16):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
let runResult = ScriptById(123).Run(#{&lt;br /&gt;
  &amp;quot;numberToRaise&amp;quot;: 4,&lt;br /&gt;
  &amp;quot;exponent&amp;quot;: 2&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;Start&amp;quot;&amp;gt;Start&amp;lt;/span&amp;gt;&lt;br /&gt;
||Dictionary of parameters&lt;br /&gt;
||Starts the script. The function call doesn&#039;t wait for the script run to complete (i.e., asynchronous behavior) which is same as starting the script in the [[Managing_Scripts#Starting_Script|Workspace]].&lt;br /&gt;
&lt;br /&gt;
Parameters to the script can be provided as a dictionary of name-value pairs (which is not possible when script is started in the Workspace). Return value is the script run id (integer) if the script was started. If the script is already running, return value is &#039;&#039;null&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Example: Start script (without parameters) and store the script run id:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
let runId = ScriptById(1).Start();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Start script with passing parameters:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ScriptById(1).Start(#{&lt;br /&gt;
  &amp;quot;variable1&amp;quot;: &amp;quot;val1&amp;quot;,&lt;br /&gt;
  &amp;quot;variable2&amp;quot;: 5&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||Stop&lt;br /&gt;
||&lt;br /&gt;
||Stops the script. The operation doesn&#039;t wait for the stopping to complete (i.e., asynchronous behavior) which is same as stopping the script in the [[Managing_Scripts#Stopping_Script|Workspace]]. Depending on the operation that the script is performing, the stopping might take some time.&lt;br /&gt;
&lt;br /&gt;
Return value is the script run id (integer) if the script was running. If the script isn&#039;t running, the return value is &#039;&#039;null&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
let runId = ScriptById(1).Stop();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Function to get a script by the script id:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!&#039;&#039;&#039;Functions&#039;&#039;&#039;&lt;br /&gt;
!&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||ScriptById&lt;br /&gt;
||&lt;br /&gt;
* Script id (Integer)&lt;br /&gt;
||&lt;br /&gt;
Returns Script object corresponding to the given script id. If script with the given id doesn&#039;t exist or user doesn&#039;t have permissions to it, an error is given.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== User/Group ==&lt;br /&gt;
User objects represents users and user groups. Note that some properties can only be used for users and some for groups.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!&#039;&#039;&#039;User/group properties&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||CreatedBy (User)&lt;br /&gt;
||Returns the user who created the user.&lt;br /&gt;
|-&lt;br /&gt;
||CreatedDate (DateTime)&lt;br /&gt;
||Returns the date when the user was created.&lt;br /&gt;
|-&lt;br /&gt;
||DefaultDashboard (String)&lt;br /&gt;
||Returns the configured [[User_Settings#Starting_dashboard|starting dashboard]] (&amp;quot;default dashboard&amp;quot;) identifier for a group (for users, the starting dashboard cannot be configured). The starting dashboard is automatically opened when a user logs in.&lt;br /&gt;
|-&lt;br /&gt;
||Description (String)&lt;br /&gt;
||Description of the user.&lt;br /&gt;
|-&lt;br /&gt;
||EffectiveDefaultDashboard (String)&lt;br /&gt;
||Returns the [[User_Settings#Starting_dashboard|starting dashboard]] of a user. Value &#039;&#039;null&#039;&#039; means that the user doesn&#039;t have a starting dashboard. The starting dashboard comes from the user&#039;s groups. If multiple of user&#039;s groups have the starting dashboard defined, the user&#039;s starting dashboard will be taken from a group having alphabetically the first name.&lt;br /&gt;
|-&lt;br /&gt;
||Email (String)&lt;br /&gt;
||Email address of the user.&lt;br /&gt;
|-&lt;br /&gt;
||FullName (String)&lt;br /&gt;
||Full name of the user or group name.&lt;br /&gt;
|-&lt;br /&gt;
||GlobalPermissions (String*)&lt;br /&gt;
||Array of global [[Roles and Permissions#Global_and_Project_Roles|permissions]] of the user. Global permissions come from the global roles assigned to the user and groups that the user belongs to. Note that to get the effective permissions for certain objects, also project specific permissions need to be taken into account.&lt;br /&gt;
|-&lt;br /&gt;
||GroupMemberNames (String*)&lt;br /&gt;
||Array of names of members of a user group. This property is available for groups.&lt;br /&gt;
|-&lt;br /&gt;
||GroupMembers (User*)&lt;br /&gt;
||Array of members of a user group. This property is available for groups.&lt;br /&gt;
|-&lt;br /&gt;
||GroupNames (String*)&lt;br /&gt;
||Array of names of user groups the user belongs to. This property is available for users.&lt;br /&gt;
|-&lt;br /&gt;
||Groups (User*)&lt;br /&gt;
||Array of user groups the user belongs to. This property is available for users.&lt;br /&gt;
|-&lt;br /&gt;
||HasPassword (Boolean)&lt;br /&gt;
||Returns true if user has a password defined in QPR ProcessAnalyzer and thus user can authenticate using the password. If user doesn&#039;t have a password, the SAML authentication is the only way to log in. &#039;&#039;ManageUsers&#039;&#039; permission is needed to access this property for other users.&lt;br /&gt;
|-&lt;br /&gt;
||Id (Integer)&lt;br /&gt;
||Id of the user, which is unique for every user.&lt;br /&gt;
|-&lt;br /&gt;
||IsActive (Boolean)&lt;br /&gt;
||Returns true only if the user is active (not disabled).&lt;br /&gt;
|-&lt;br /&gt;
||IsGroup (Boolean)&lt;br /&gt;
||Returns true if the user is a user group.&lt;br /&gt;
|-&lt;br /&gt;
||IsLocked (Boolean)&lt;br /&gt;
||Returns true if user account is currently [[User_Session_Management#Preventing_password_guessing_attacks|locked]]. &#039;&#039;ManageUsers&#039;&#039; permission is needed to access this property.&lt;br /&gt;
|-&lt;br /&gt;
||LastLockedDate (DateTime)&lt;br /&gt;
||Returns date when user account was locked the last time. Returns &#039;&#039;null&#039;&#039; if the user account has never been locked. &#039;&#039;ManageUsers&#039;&#039; permission is needed to access this property.&lt;br /&gt;
|-&lt;br /&gt;
||LastLoginDate (DateTime)&lt;br /&gt;
||Returns date when the user made last successful login. &#039;&#039;ManageUsers&#039;&#039; permission is needed to access this property for other users.&lt;br /&gt;
|-&lt;br /&gt;
||LastModifiedBy (User)&lt;br /&gt;
||Returns the user who last modified this user.&lt;br /&gt;
|-&lt;br /&gt;
||LastModifiedDate (DateTime)&lt;br /&gt;
||Returns the date when the user was last modified.&lt;br /&gt;
|-&lt;br /&gt;
||Name (String)&lt;br /&gt;
||Login name of the user or group.&lt;br /&gt;
|-&lt;br /&gt;
||Roles (Object**)&lt;br /&gt;
||&lt;br /&gt;
Returns all roles of the user (both global and project roles) as a nested array structure.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ToJson(Users.Where(name == &amp;quot;qpr&amp;quot;).Roles)&lt;br /&gt;
Returns (for example):&lt;br /&gt;
[&lt;br /&gt;
  [{&amp;quot;calcId&amp;quot;: &amp;quot;Project:1&amp;quot;}, &amp;quot;Administrator&amp;quot;],&lt;br /&gt;
  [{&amp;quot;calcId&amp;quot;: &amp;quot;Project:2&amp;quot;}, &amp;quot;Analyzer&amp;quot;],&lt;br /&gt;
  [{&amp;quot;calcId&amp;quot;: &amp;quot;Project:3&amp;quot;}, &amp;quot;Viewer&amp;quot;],&lt;br /&gt;
  [null, &amp;quot;RunScripts&amp;quot;],&lt;br /&gt;
  [null, &amp;quot;Administrator&amp;quot;]&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!&#039;&#039;&#039;User/group functions&#039;&#039;&#039;&lt;br /&gt;
!&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||EffectivePermissionsFor (String Array)&lt;br /&gt;
||&lt;br /&gt;
* Project to get permissions&lt;br /&gt;
||&lt;br /&gt;
Returns effective (actual) permission of the user to the given project. Project is given as a [[#Project|project object]] (not as a project id). Effective permissions determine the actual permissions that the user has, i.e. a combination of all permissions assigned to the user and groups the user belong to, including both project specific and global roles.&lt;br /&gt;
&lt;br /&gt;
Permissions for the EffectivePermissionsFor function are as follows:&lt;br /&gt;
* All users can query their own permissions&lt;br /&gt;
* To get permissions for any user, the user needs to have [[Roles_and_Permissions|ManageUsers permission]].&lt;br /&gt;
&lt;br /&gt;
Note that &#039;&#039;inactive&#039;&#039; users don&#039;t have any effective permissions, so the EffectivePermissionsFor function does not return any permissions for those users.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
UserById(1).EffectivePermissionsFor(ModelById(2).Project)&lt;br /&gt;
Returns (for example): [&amp;quot;EditDashboards&amp;quot;, &amp;quot;Filtering&amp;quot;, &amp;quot;GenericRead&amp;quot;]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||GetAttribute&lt;br /&gt;
||&lt;br /&gt;
||&lt;br /&gt;
Returns user attribute value by given attribute name and optionally by the model/project/dashboard context. Supported data types are String, Integer, Float, and DateTime. To store more complex data types, data can be converted into json and stored as string. If the attribute doesn&#039;t exist, null is returned.&lt;br /&gt;
&lt;br /&gt;
For example, if using dashboard as context, the attributes are effectively bound to each user and each dashboard separately. Thus, there can be several attributes with the same name as long as the dashboard is different.&lt;br /&gt;
&lt;br /&gt;
Parameters:&lt;br /&gt;
# &#039;&#039;&#039;Attribute name&#039;&#039;&#039; (String): Name of the attribute.&lt;br /&gt;
# &#039;&#039;&#039;Attribute context&#039;&#039;&#039; (Project/Model/Dashboard): Optional context object the attribute is linked to.&lt;br /&gt;
&lt;br /&gt;
Users have permissions to get attributes for themselves, and also (administrator) users with global &#039;&#039;ManageUsers&#039;&#039; permission can get attributes for all users. In addition, if using the context object, the &#039;&#039;GenericRead&#039;&#039; permission is required for the context object.&lt;br /&gt;
&lt;br /&gt;
Example: Get user attribute MyDataValue for myself:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CurrentUser&lt;br /&gt;
  .GetAttribute(&amp;quot;MyDataValue&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Get user attribute MyDataValue for user John:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Users&lt;br /&gt;
  .Where(Name==&amp;quot;John&amp;quot;)&lt;br /&gt;
  .GetAttribute(&amp;quot;MyDataValue&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Get user attribute MyDataValue for user 1 related to dashboard id 1:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
UserById(1)&lt;br /&gt;
  .GetAttribute(&amp;quot;MyDataValue&amp;quot;, DashboardById(1));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||SetAttribute&lt;br /&gt;
||&lt;br /&gt;
||&lt;br /&gt;
Sets user attribute value for given attribute name and optionally for the model/project/dashboard context. Supported data types are String, Integer, Float, and DateTime. To store more complex data types, data can be converted into json and stored as string. If setting value &#039;&#039;null&#039;&#039;, the user attribute is removed. Required permissions are same as in the GetAttribute function.&lt;br /&gt;
&lt;br /&gt;
Parameters:&lt;br /&gt;
# &#039;&#039;&#039;Attribute name&#039;&#039;&#039; (String): Name of the attribute.&lt;br /&gt;
# &#039;&#039;&#039;Attribute value&#039;&#039;&#039; (String/Integer/Float/DateTime): Attribute value to be stored.&lt;br /&gt;
# &#039;&#039;&#039;Attribute context&#039;&#039;&#039; (Project/Model/Dashboard): Optional context object the attribute value is linked to.&lt;br /&gt;
&lt;br /&gt;
Example: Set user attribute MyDataValue for myself:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CurrentUser&lt;br /&gt;
  .SetAttribute(&amp;quot;MyDataValue &amp;quot;, &amp;quot;value&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Set value 123 as user attribute MyDataValue for user John:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Users&lt;br /&gt;
  .Where(Name==&amp;quot;John&amp;quot;)&lt;br /&gt;
  .SetAttribute(&amp;quot;MyDataValue&amp;quot;, 123);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Set current time as user attribute MyDataValue for user 1 related to dashboard id 1:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
UserById(1)&lt;br /&gt;
  .GetAttribute(&amp;quot;MyDataValue&amp;quot;, Now, DashboardById(1));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Function to get User by user id:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!&#039;&#039;&#039;Functions&#039;&#039;&#039;&lt;br /&gt;
!&#039;&#039;&#039;Parameters&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||UserById (User)&lt;br /&gt;
||&lt;br /&gt;
* User id (Integer)&lt;br /&gt;
||&lt;br /&gt;
Returns User object that has the provided user id. Also groups can be queried with this function. Returns an access denied error if the user with given id does not exist or the current user does not have access to it.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28189</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28189"/>
		<updated>2026-04-27T11:08:48Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-64041&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API key. Both the authentication methods can be configured at the same time to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication, set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_CONFIGURATION database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
Some clients use the [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint: /.well-known/openid-configuration. To get this endpoint working when QPR ProcessAnalyzer is hosted in Windows in IIS, the following setup is required:&lt;br /&gt;
&lt;br /&gt;
Add an IIS rewrite rule and a CORS header at the IIS root-level &#039;&#039;&#039;web.config&#039;&#039;&#039;. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
== Creating MCP Tools ==&lt;br /&gt;
MCP tools are implemented using [[Managing_Scripts|scripts]] written in QPR ProcessAnalyzer expression language. A script will be added as the MCP tool when the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox is enabled in the [[Managing_Scripts#Script_Properties|Script Properties]]. Only system administrator users can enable the MCP tool checkbox. Also, scripts that are MCP tools, only system administrators can modify them because any changes to the MCP interface is restricted to system administrators for security reasons.&lt;br /&gt;
&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# Open or create the script.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab and select the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;Description&#039;&#039;&#039; tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
=== MCP Tool Configuration ===&lt;br /&gt;
Every script can define its own &#039;&#039;&#039;McpTool&#039;&#039;&#039; configuration as JSON. Supported values are same as [https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool here], except for the &#039;&#039;&#039;name&#039;&#039;&#039; which is always generated automatically and can&#039;t be overridden. Defining the McpTool configuration will override any default configurations generated for scripts automatically by QPR ProcessAnalyzer. For example, specifying the value for &amp;quot;title&amp;quot; here will override the default functionality of using script&#039;s name as title of the tool.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following JSON configures the MCP tool with a customized title and description, as well as some additional [https://github.com/modelcontextprotocol/csharp-sdk/blob/main/src/ModelContextProtocol.Core/Protocol/ToolAnnotations.cs MCP tool annotations]:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Example MCP tool title&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Example MCP tool description&amp;quot;,&lt;br /&gt;
    &amp;quot;annotations&amp;quot;: {&lt;br /&gt;
        &amp;quot;destructiveHint&amp;quot;: true,&lt;br /&gt;
        &amp;quot;idempotentHint&amp;quot;: true,&lt;br /&gt;
        &amp;quot;openWorldHint&amp;quot;: true,&lt;br /&gt;
        &amp;quot;readOnlyHint&amp;quot;: false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Defining Input Parameters ===&lt;br /&gt;
MCP tool input parameters are defined using a JSON schema following the [https://modelcontextprotocol.io/specification/2025-11-25/basic#json-schema-usage Model Context Protocol&#039;s JSON Schema]. Each supported input parameter is listed under &#039;&#039;&#039;properties&#039;&#039;&#039;. By default, script don&#039;t enforce any schema.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following schema defines a script with five different types of parameters:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;stringParameter&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;String parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
	&amp;quot;numberParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;number&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Number parameter&amp;quot;&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;booleanParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;boolean&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Boolean parameter&amp;quot;&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;arrayParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Array parameter&amp;quot;,&lt;br /&gt;
	  &amp;quot;nullable&amp;quot;: true,&lt;br /&gt;
	  &amp;quot;items&amp;quot;: {&lt;br /&gt;
		  &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
	  }&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;objectParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Object parameter&amp;quot;,&lt;br /&gt;
	  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
	    &amp;quot;inner&amp;quot;: {&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;}&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
After this, the tool can be called, for example, with the following set of parameters:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	{ &amp;quot;stringParameter&amp;quot;, &amp;quot;bar&amp;quot; },&lt;br /&gt;
	{ &amp;quot;numberParameter&amp;quot;, 123.456 },&lt;br /&gt;
	{ &amp;quot;booleanParameter&amp;quot;, true },&lt;br /&gt;
	{ &amp;quot;arrayParameter&amp;quot;, new Object[] { 1, 2, 3 } },&lt;br /&gt;
	{&lt;br /&gt;
		&amp;quot;objectParameter&amp;quot;, new Dictionary&amp;lt;string, object&amp;gt;&lt;br /&gt;
		{&lt;br /&gt;
			{ &amp;quot;inner&amp;quot;, &amp;quot;value&amp;quot; }&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Defining Structured Tool Output ===&lt;br /&gt;
Structured tool output is described using a JSON schema following the [https://modelcontextprotocol.io/specification/2025-11-25/basic#json-schema-usage Model Context Protocol&#039;s JSON Schema]. By default, scripts don&#039;t enforce any schema and the result is considered to be just text.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following example configures the script&#039;s return value to contain an object having five different types of properties.:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;string&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;String parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;number&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;number&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Number parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;boolean&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;boolean&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Boolean parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;array&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Array parameter&amp;quot;,&lt;br /&gt;
        &amp;quot;nullable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;items&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;object&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Object parameter&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;inner&amp;quot;: {&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;}&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing MCP tools in QPR ProcessAnalyzer ==&lt;br /&gt;
When developing MCP tools, it might be useful try test them in QPR ProcessAnalyzer before publishing as MCP tools. Scripts (used as MCP tools) can be called in the [[Navigation_Menu#Expression_Designer|Expression Designer]]. The following example expression calls a script with some parameters and shows the return value as json:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot; line&amp;gt;&lt;br /&gt;
let returnValue = ScriptById(1).Run(#{&lt;br /&gt;
  &amp;quot;string_param&amp;quot;: &amp;quot;value1&amp;quot;,&lt;br /&gt;
  &amp;quot;integer_param&amp;quot;: 123,&lt;br /&gt;
  &amp;quot;boolean_param&amp;quot;: false,&lt;br /&gt;
  &amp;quot;array_param&amp;quot;: [&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;]&lt;br /&gt;
});&lt;br /&gt;
return ToJson(returnValue);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_CONFIGURATION database table.&lt;br /&gt;
* &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_CONFIGURATION database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)]. This is often automatically done by MCP Client software.&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
* Connect to Server: &lt;br /&gt;
** In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., https://your-pa-server/qprpa/api/mcp)&lt;br /&gt;
** Select Streamable HTTP as the transport type.&lt;br /&gt;
** Select &amp;quot;Via Proxy&amp;quot; as connection type.&lt;br /&gt;
* Authenticate: &lt;br /&gt;
** If using API Key-based authentication, configure &amp;quot;X-Mcp-Api-Key&amp;quot; as additional custom header with the value specified in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting of the PA server.&lt;br /&gt;
** If using OAuth, set one of the accepted audience values to Authentication/OAuth 2.0 Flow/Client ID (or leave it empty if DCR is enabled).&lt;br /&gt;
*** Open Auth Settings&lt;br /&gt;
*** Click &amp;quot;Quick OAuth Flow&amp;quot;-button.&lt;br /&gt;
**** Perform OAuth authorization using the built-in OAuth provider.&lt;br /&gt;
**** Provided that the authentication has been configured correctly, a successful authentication message should be shown.&lt;br /&gt;
** Click Connect.&lt;br /&gt;
* List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool created for a parameterless QPR ProcessAnalyzer script having id 216, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
  &amp;quot;params&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Script-216&amp;quot;,&lt;br /&gt;
    &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
    &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
      &amp;quot;progressToken&amp;quot;: 0&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=Managing_Scripts&amp;diff=28188</id>
		<title>Managing Scripts</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=Managing_Scripts&amp;diff=28188"/>
		<updated>2026-04-27T11:07:58Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-64041&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In QPR ProcessAnalyzer, scripts can be used for ETL tasks and to automate routines. Scripts are managed in the [[QPR_ProcessAnalyzer_Project_Workspace|Project Workspace]].&lt;br /&gt;
&lt;br /&gt;
=== Running vs. Calling Scripts ===&lt;br /&gt;
&#039;&#039;Running&#039;&#039; a script means starting executing a stored script, which can be done in the UI or using the ScriptLauncher. A script can also &#039;&#039;call&#039;&#039; other scripts during the run. The differences between the running and calling are:&lt;br /&gt;
* Script can run only once at a time, whereas there are no limitations on how many times a script can be called at the same time&lt;br /&gt;
* Script log is written to the running script. No script log is written to the called script.&lt;br /&gt;
* Script status shows whether the script is being run or not. The status does not change, when a script is called from other script.&lt;br /&gt;
&lt;br /&gt;
When a script is running, it&#039;s not possible to start another run of the same script, so the first run needs to end to start new. Scripts can call other scripts and a called scripts can run multiple times simultaneously. In the stack of called scripts, the script log is generated to the top level script. Also the top level script shows that it&#039;s running and the called scripts do not.&lt;br /&gt;
&lt;br /&gt;
=== Scripts List ===&lt;br /&gt;
When selecting a project and opening the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab, all scripts in the project can be seen. Scripts list shows following information:&lt;br /&gt;
* &#039;&#039;&#039;Name&#039;&#039;&#039;: Name of the script.&lt;br /&gt;
* &#039;&#039;&#039;Status&#039;&#039;&#039;: Status of the script, which is one of following: &#039;&#039;Ready&#039;&#039;, &#039;&#039;Running&#039;&#039; or &#039;&#039;Stopping&#039;&#039;. For more information about script statuses, see below.&lt;br /&gt;
* &#039;&#039;&#039;Last run duration&#039;&#039;&#039;: Duration of the last ended run of the script (the last run result can be any).&lt;br /&gt;
* &#039;&#039;&#039;Last run date&#039;&#039;&#039;: Date and time when the last run ended. If you need to know the last run start time, subtract the &#039;&#039;Last run duration&#039;&#039; from this time.&lt;br /&gt;
* &#039;&#039;&#039;Last run result&#039;&#039;&#039;: Result of the last run of the script. Either of following: &#039;&#039;Completed&#039;&#039;, &#039;&#039;Failed&#039;&#039; or &#039;&#039;Aborted&#039;&#039;. For more information about last run results, see below.&lt;br /&gt;
* &#039;&#039;&#039;Id&#039;&#039;&#039;: Script id that uniquely identifies the script in the system.&lt;br /&gt;
&lt;br /&gt;
Scrips are in either of following statuses:&lt;br /&gt;
* &#039;&#039;&#039;Ready&#039;&#039;&#039;: Script is currently not running, and can be started.&lt;br /&gt;
* &#039;&#039;&#039;Running&#039;&#039;&#039;: Script is currently running, and the script can be stopped. When a script is running, another run of the same script cannot be started.&lt;br /&gt;
* &#039;&#039;&#039;Stopping&#039;&#039;&#039;: Script is currently being stopped. When a script is in this status, the script cannot be started nor stopped, so you need to wait for the script to stop. There may be a delay in stopping a script, depending on the operation currently performed by the script.&lt;br /&gt;
&lt;br /&gt;
The last script run result can be either of the following:&lt;br /&gt;
* &#039;&#039;&#039;Completed&#039;&#039;&#039;: The last run ended successfully, i.e. without any errors or exceptions. Note that despite of the technically successful run, the script might still not work as intended.&lt;br /&gt;
* &#039;&#039;&#039;Failed&#039;&#039;&#039;: The last run ended to an error or exception. To see more information about the reason of the failure, see the [[#Viewing_Script_Log|last run log]].&lt;br /&gt;
* &#039;&#039;&#039;Aborted&#039;&#039;&#039;: The last run was stopped by a user, so the script did not run till the end.&lt;br /&gt;
&lt;br /&gt;
=== Script Properties ===&lt;br /&gt;
To open Script Properties, &#039;&#039;&#039;right-click&#039;&#039;&#039; the script on the Scripts tab in the Workspace and select &#039;&#039;&#039;Properties&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
The Script Properties lists the following information on the &#039;&#039;&#039;General&#039;&#039;&#039; tab:&lt;br /&gt;
* &#039;&#039;&#039;Script ID&#039;&#039;&#039;: A unique ID in the system.&lt;br /&gt;
* &#039;&#039;&#039;Language&#039;&#039;&#039;: The script&#039;s language, either &amp;quot;SQL&amp;quot; or &amp;quot;Expression&amp;quot;.&lt;br /&gt;
* &#039;&#039;&#039;Status&#039;&#039;&#039;: As above in Scripts List.&lt;br /&gt;
* &#039;&#039;&#039;Last run start&#039;&#039;&#039;: Date and time when the last run started.&lt;br /&gt;
* &#039;&#039;&#039;Last run end&#039;&#039;&#039;: As &amp;quot;Last run date&amp;quot; above in Scripts List.&lt;br /&gt;
* &#039;&#039;&#039;Last run duration&#039;&#039;&#039;: As above in Scripts List.&lt;br /&gt;
* &#039;&#039;&#039;Last run result&#039;&#039;&#039;: As above in Scripts List.&lt;br /&gt;
* &#039;&#039;&#039;Last modified&#039;&#039;&#039;: Date and time when the script was last modified.&lt;br /&gt;
* &#039;&#039;&#039;Last modified by&#039;&#039;&#039;: User who last modified the script.&lt;br /&gt;
* &#039;&#039;&#039;Created&#039;&#039;&#039;: Date and time when the script was created.&lt;br /&gt;
* &#039;&#039;&#039;Created by&#039;&#039;&#039;: User who created the script.&lt;br /&gt;
&lt;br /&gt;
The script Properties has the following information on the &#039;&#039;&#039;Input&#039;&#039; tab:&lt;br /&gt;
* &#039;&#039;&#039;JSON schema for input parameters&#039;&#039;&#039;: A text box for defining the [[QPR_ProcessAnalyzer_as_MCP_Server#Defining_Input_Parameters|input parameters]].&lt;br /&gt;
&lt;br /&gt;
The script Properties has the following information on the &#039;&#039;&#039;Output&#039;&#039; tab:&lt;br /&gt;
* &#039;&#039;&#039;JSON schema for script output&#039;&#039;&#039;: A text box for defining the [[QPR_ProcessAnalyzer_as_MCP_Server#Defining_Structured_Tool_Output|output parameters]].&lt;br /&gt;
&lt;br /&gt;
The Script Properties has the following information on the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab:&lt;br /&gt;
* &#039;&#039;&#039;MCP tool&#039;&#039;&#039;: A checkbox to select whether the script can be used as an [[QPR_ProcessAnalyzer_as_MCP_Server|MCP]] tool. Only System Administrators can modify this setting. Note that once a script has been defined as an MCP tool, only System Administrators are able to modify the script itself.&lt;br /&gt;
* &#039;&#039;&#039;JSON for MCP tool configuration&#039;&#039;&#039;: A text box for defining the [[QPR_ProcessAnalyzer_as_MCP_Server#MCP_Tool_Configuration|MCP tool configuration]].&lt;br /&gt;
&lt;br /&gt;
The Script Properties has the following information on the &#039;&#039;&#039;Description&#039;&#039;&#039; tab:&lt;br /&gt;
* A textbox to edit the description of the script.&lt;br /&gt;
&lt;br /&gt;
=== Editing Script ===&lt;br /&gt;
Open the scripts editor as follows:&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and in the right-click context menu select &#039;&#039;&#039;Edit&#039;&#039;&#039;. Alternatively, you can hover the script and click the &#039;&#039;Edit&#039;&#039; button in the end of the row.&lt;br /&gt;
&lt;br /&gt;
If the script has been defined as an MCP tool, only System Administrators are able to edit the script.&lt;br /&gt;
&lt;br /&gt;
The script editor can show multiple scripts in the tabs, allowing to easily switch between the scrips. The editor remembers all scripts that have been opened during the session.&lt;br /&gt;
&lt;br /&gt;
In the script editor, you can:&lt;br /&gt;
* Run the script by clicking the &#039;&#039;&#039;Run&#039;&#039;&#039; button.&lt;br /&gt;
* Stop a running script by clicking the &#039;&#039;&#039;Stop&#039;&#039;&#039; button.&lt;br /&gt;
* Save a script having unsaved changes by clicking the &#039;&#039;&#039;Save&#039;&#039;&#039; button.&lt;br /&gt;
* To run a script having unsaved changes, click the &#039;&#039;&#039;Save and Run&#039;&#039;&#039; button. Note that the script needs to be saved to run it.&lt;br /&gt;
* To go back to the list of scripts, click the &#039;&#039;&#039;Go back&#039;&#039;&#039; button. If there are unsaved changes in any of the opened scripts, you need to either save or cancel the changes.&lt;br /&gt;
* To close a script, click the &#039;&#039;Close&#039;&#039; button for the tab showing the script. If there are unsaved changes, you need to either save or cancel changes.&lt;br /&gt;
&lt;br /&gt;
=== Starting Script ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and in the right-click context menu select &#039;&#039;&#039;Run&#039;&#039;&#039;. Alternatively, you can hover the script and click the &#039;&#039;Run&#039;&#039; button in the end of the row.&lt;br /&gt;
&lt;br /&gt;
Note that when running a script in the UI, the script must not contain commands where &#039;&#039;ExecuteInClientSide&#039;&#039; is enabled, because that is only supported when running scripts using [[QPR_ProcessAnalyzer_ScriptLauncher|QPR ScriptLauncher]].&lt;br /&gt;
&lt;br /&gt;
=== Stopping Script ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and from the right-click context menu select &#039;&#039;&#039;Stop&#039;&#039;&#039;. Alternatively, you can hover the script and click the &#039;&#039;Stop&#039;&#039; button in the end of the row.&lt;br /&gt;
&lt;br /&gt;
Note that it may take a while for a script to actually stop, depending on what kind of operation the script is executing when it&#039;s stopped.&lt;br /&gt;
&lt;br /&gt;
=== Viewing Script Log ===&lt;br /&gt;
It&#039;s possible to see the script log of the last run, and monitor the currently running script progress. Logs for older runs are not available in the UI, nut they are stored by the system.&lt;br /&gt;
&lt;br /&gt;
To see the logs:&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and in the right-click context menu select either &#039;&#039;&#039;View last run log&#039;&#039;&#039; or &#039;&#039;&#039;View current run log&#039;&#039;&#039;. (The script needs to be running to open the current run log.)&lt;br /&gt;
# If keeping the current run log open, the latest log entries are updated automatically every two seconds.&lt;br /&gt;
&lt;br /&gt;
More information about [[QPR_ProcessAnalyzer_Logs#Script_Log|Script Log]].&lt;br /&gt;
&lt;br /&gt;
=== Creating Script ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where you want to create a script.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Click the &#039;&#039;&#039;New&#039;&#039;&#039; button and click &#039;&#039;&#039;Script&#039;&#039;&#039;. Define a name for the script and the scripting &#039;&#039;&#039;Language&#039;&#039;&#039; (either &#039;&#039;&#039;Expression&#039;&#039;&#039; or &#039;&#039;&#039;SQL&#039;&#039;&#039;), and then click &#039;&#039;&#039;Create&#039;&#039;&#039;. Note that script names must be unique within a project.&lt;br /&gt;
&lt;br /&gt;
Note that the scripting language cannot be changed after the script has been created, so a new script needs to be created to change the language.&lt;br /&gt;
&lt;br /&gt;
Note that each script in the same project needs to have a unique name.&lt;br /&gt;
&lt;br /&gt;
=== Deleting Script ===&lt;br /&gt;
# Select the project where the script(s) to be deleted are located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select one or several scripts to be deleted.&lt;br /&gt;
# Click the &#039;&#039;&#039;Delete&#039;&#039;&#039; button and click &#039;&#039;&#039;Delete&#039;&#039;&#039; to the confirmation message.&lt;br /&gt;
&lt;br /&gt;
Note that if the script is being run, it cannot be deleted.&lt;br /&gt;
&lt;br /&gt;
=== Renaming Script ===&lt;br /&gt;
# Select the project where the script to be renamed is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script to be renamed.&lt;br /&gt;
# Click the &#039;&#039;&#039;Rename&#039;&#039;&#039; button.&lt;br /&gt;
# Change the script name in the opening dialog and click &#039;&#039;&#039;OK&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Moving Script ===&lt;br /&gt;
Scripts can be moved by dragging them with the left mouse button from the right side list to the target project in the left side hierarchy. Alternatively, you can first select the scripts, then from the right-click context menu select &#039;&#039;&#039;Move to&#039;&#039;&#039; and finally select the target project.&lt;br /&gt;
&lt;br /&gt;
=== Duplicating Script ===&lt;br /&gt;
# Select the project where the script to be duplicated is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script to be duplicated.&lt;br /&gt;
# Click the &#039;&#039;&#039;Duplicate&#039;&#039;&#039; button. A duplicate of the script is created.&lt;br /&gt;
&lt;br /&gt;
=== Viewing Script Run Results ===&lt;br /&gt;
Script runs can be [[Managing_Scripts#Running_Script|started]] and [[Managing_Scripts#Stopping_Script|stopped]] in the UI. Note that when running scripts using the UI, return values or results of the script cannot be viewed. If you want to use scripts that return data, there are following options:&lt;br /&gt;
* Script can write data to the script log&lt;br /&gt;
* Script can write data to a datatable&lt;br /&gt;
* Script can be called from a dashboard and use the dashboard to present the returned data (see more below).&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28187</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28187"/>
		<updated>2026-04-27T11:06:04Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-64041&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API key. Both the authentication methods can be configured at the same time to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication, set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_CONFIGURATION database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
Some clients use the [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint: /.well-known/openid-configuration. To get this endpoint working when QPR ProcessAnalyzer is hosted in Windows in IIS, the following setup is required:&lt;br /&gt;
&lt;br /&gt;
Add an IIS rewrite rule and a CORS header at the IIS root-level &#039;&#039;&#039;web.config&#039;&#039;&#039;. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
== Creating MCP Tools ==&lt;br /&gt;
MCP tools are implemented using [[Managing_Scripts|scripts]] written in QPR ProcessAnalyzer expression language. A script will be added as the MCP tool when the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox is enabled in the [[Managing_Scripts#Script_Properties|Script Properties]]. Only system administrator users can enable the MCP tool checkbox. Also, scripts that are MCP tools, only system administrators can modify them because any changes to the MCP interface is restricted to system administrators for security reasons.&lt;br /&gt;
&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# Open or create the script.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab and select the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;Description&#039;&#039;&#039; tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
=== MCP Tool Configuration ===&lt;br /&gt;
Every script can define its own &#039;&#039;&#039;McpTool&#039;&#039;&#039; configuration as JSON. Supported values are same as [https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool here], except for the &#039;&#039;&#039;name&#039;&#039;&#039; which is always generated automatically and can&#039;t be overridden. Defining the McpTool configuration will override any default configurations generated for scripts automatically by QPR ProcessAnalyzer. For example, specifying the value for &amp;quot;title&amp;quot; here will override the default functionality of using script&#039;s name as title of the tool.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following JSON configures the MCP tool with a customized title and description, as well as some additional [https://github.com/modelcontextprotocol/csharp-sdk/blob/main/src/ModelContextProtocol.Core/Protocol/ToolAnnotations.cs MCP tool annotations]:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Example MCP tool title&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Example MCP tool description&amp;quot;,&lt;br /&gt;
    &amp;quot;annotations&amp;quot;: {&lt;br /&gt;
        &amp;quot;destructiveHint&amp;quot;: true,&lt;br /&gt;
        &amp;quot;idempotentHint&amp;quot;: true,&lt;br /&gt;
        &amp;quot;openWorldHint&amp;quot;: true,&lt;br /&gt;
        &amp;quot;readOnlyHint&amp;quot;: false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Defining Input Parameters ===&lt;br /&gt;
MCP tool input parameters are defined using a JSON schema following the [https://modelcontextprotocol.io/specification/2025-11-25/basic#json-schema-usage Model Context Protocol&#039;s JSON Schema]. Each supported input parameter is listed under &#039;&#039;&#039;properties&#039;&#039;&#039;. By default, script don&#039;t enforce any schema.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following schema defines a script with five different types of parameters:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;stringParameter&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;String parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
	&amp;quot;numberParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;number&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Number parameter&amp;quot;&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;booleanParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;boolean&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Boolean parameter&amp;quot;&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;arrayParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Array parameter&amp;quot;,&lt;br /&gt;
	  &amp;quot;nullable&amp;quot;: true,&lt;br /&gt;
	  &amp;quot;items&amp;quot;: {&lt;br /&gt;
		  &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
	  }&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;objectParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Object parameter&amp;quot;,&lt;br /&gt;
	  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
	    &amp;quot;inner&amp;quot;: {&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;}&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
After this, the tool can be called, for example, with the following set of parameters:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	{ &amp;quot;stringParameter&amp;quot;, &amp;quot;bar&amp;quot; },&lt;br /&gt;
	{ &amp;quot;numberParameter&amp;quot;, 123.456 },&lt;br /&gt;
	{ &amp;quot;booleanParameter&amp;quot;, true },&lt;br /&gt;
	{ &amp;quot;arrayParameter&amp;quot;, new Object[] { 1, 2, 3 } },&lt;br /&gt;
	{&lt;br /&gt;
		&amp;quot;objectParameter&amp;quot;, new Dictionary&amp;lt;string, object&amp;gt;&lt;br /&gt;
		{&lt;br /&gt;
			{ &amp;quot;inner&amp;quot;, &amp;quot;value&amp;quot; }&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When a tool is called, input is validated against the configured parameter schema. Validation is performed against the sanitized parameter collection so that empty or omitted parameter sets are handled consistently.&lt;br /&gt;
&lt;br /&gt;
=== Defining Structured Tool Output ===&lt;br /&gt;
Structured tool output is described using a JSON schema following the [https://modelcontextprotocol.io/specification/2025-11-25/basic#json-schema-usage Model Context Protocol&#039;s JSON Schema]. By default, scripts don&#039;t enforce any schema and the result is considered to be just text.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following example configures the script&#039;s return value to contain an object having five different types of properties.:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;string&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;String parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;number&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;number&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Number parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;boolean&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;boolean&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Boolean parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;array&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Array parameter&amp;quot;,&lt;br /&gt;
        &amp;quot;nullable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;items&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;object&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Object parameter&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;inner&amp;quot;: {&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;}&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing MCP tools in QPR ProcessAnalyzer ==&lt;br /&gt;
When developing MCP tools, it might be useful try test them in QPR ProcessAnalyzer before publishing as MCP tools. Scripts (used as MCP tools) can be called in the [[Navigation_Menu#Expression_Designer|Expression Designer]]. The following example expression calls a script with some parameters and shows the return value as json:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot; line&amp;gt;&lt;br /&gt;
let returnValue = ScriptById(1).Run(#{&lt;br /&gt;
  &amp;quot;string_param&amp;quot;: &amp;quot;value1&amp;quot;,&lt;br /&gt;
  &amp;quot;integer_param&amp;quot;: 123,&lt;br /&gt;
  &amp;quot;boolean_param&amp;quot;: false,&lt;br /&gt;
  &amp;quot;array_param&amp;quot;: [&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;]&lt;br /&gt;
});&lt;br /&gt;
return ToJson(returnValue);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_CONFIGURATION database table.&lt;br /&gt;
* &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_CONFIGURATION database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)]. This is often automatically done by MCP Client software.&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
* Connect to Server: &lt;br /&gt;
** In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., https://your-pa-server/qprpa/api/mcp)&lt;br /&gt;
** Select Streamable HTTP as the transport type.&lt;br /&gt;
** Select &amp;quot;Via Proxy&amp;quot; as connection type.&lt;br /&gt;
* Authenticate: &lt;br /&gt;
** If using API Key-based authentication, configure &amp;quot;X-Mcp-Api-Key&amp;quot; as additional custom header with the value specified in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting of the PA server.&lt;br /&gt;
** If using OAuth, set one of the accepted audience values to Authentication/OAuth 2.0 Flow/Client ID (or leave it empty if DCR is enabled).&lt;br /&gt;
*** Open Auth Settings&lt;br /&gt;
*** Click &amp;quot;Quick OAuth Flow&amp;quot;-button.&lt;br /&gt;
**** Perform OAuth authorization using the built-in OAuth provider.&lt;br /&gt;
**** Provided that the authentication has been configured correctly, a successful authentication message should be shown.&lt;br /&gt;
** Click Connect.&lt;br /&gt;
* List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool created for a parameterless QPR ProcessAnalyzer script having id 216, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
  &amp;quot;params&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Script-216&amp;quot;,&lt;br /&gt;
    &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
    &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
      &amp;quot;progressToken&amp;quot;: 0&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28186</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28186"/>
		<updated>2026-04-27T10:53:17Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-64041&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API key. Both the authentication methods can be configured at the same time to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication, set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_CONFIGURATION database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
Some clients use the [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint: /.well-known/openid-configuration. To get this endpoint working when QPR ProcessAnalyzer is hosted in Windows in IIS, the following setup is required:&lt;br /&gt;
&lt;br /&gt;
Add an IIS rewrite rule and a CORS header at the IIS root-level &#039;&#039;&#039;web.config&#039;&#039;&#039;. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
== Creating MCP Tools ==&lt;br /&gt;
MCP tools are implemented using [[Managing_Scripts|scripts]] written in QPR ProcessAnalyzer expression language. A script will be added as the MCP tool when the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox is enabled in the [[Managing_Scripts#Script_Properties|Script Properties]]. Only system administrator users can enable the MCP tool checkbox. Also, scripts that are MCP tools, only system administrators can modify them because any changes to the MCP interface is restricted to system administrators for security reasons.&lt;br /&gt;
&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# Open or create the script.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab and select the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;Description&#039;&#039;&#039; tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
=== Defining Input Parameters ===&lt;br /&gt;
MCP tool input parameters are defined using a JSON schema following the [https://modelcontextprotocol.io/specification/2025-11-25/basic#json-schema-usage Model Context Protocol&#039;s JSON Schema]. Each supported input parameter is listed under &#039;&#039;&#039;properties&#039;&#039;&#039;. By default, script don&#039;t enforce any schema.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following schema defines a script with five different types of parameters:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;stringParameter&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;String parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
	&amp;quot;numberParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;number&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Number parameter&amp;quot;&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;booleanParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;boolean&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Boolean parameter&amp;quot;&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;arrayParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Array parameter&amp;quot;,&lt;br /&gt;
	  &amp;quot;nullable&amp;quot;: true,&lt;br /&gt;
	  &amp;quot;items&amp;quot;: {&lt;br /&gt;
		  &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
	  }&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;objectParameter&amp;quot;: {&lt;br /&gt;
	  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
	  &amp;quot;description&amp;quot;: &amp;quot;Object parameter&amp;quot;,&lt;br /&gt;
	  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
	    &amp;quot;inner&amp;quot;: {&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;}&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
After this, the tool can be called, for example, with the following set of parameters:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	{ &amp;quot;stringParameter&amp;quot;, &amp;quot;bar&amp;quot; },&lt;br /&gt;
	{ &amp;quot;numberParameter&amp;quot;, 123.456 },&lt;br /&gt;
	{ &amp;quot;booleanParameter&amp;quot;, true },&lt;br /&gt;
	{ &amp;quot;arrayParameter&amp;quot;, new Object[] { 1, 2, 3 } },&lt;br /&gt;
	{&lt;br /&gt;
		&amp;quot;objectParameter&amp;quot;, new Dictionary&amp;lt;string, object&amp;gt;&lt;br /&gt;
		{&lt;br /&gt;
			{ &amp;quot;inner&amp;quot;, &amp;quot;value&amp;quot; }&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When a tool is called, input is validated against the configured parameter schema. Validation is performed against the sanitized parameter collection so that empty or omitted parameter sets are handled consistently.&lt;br /&gt;
&lt;br /&gt;
=== Defining Structured Tool Output ===&lt;br /&gt;
Structured tool output is described using a JSON schema following the [https://modelcontextprotocol.io/specification/2025-11-25/basic#json-schema-usage Model Context Protocol&#039;s JSON Schema]. By default, scripts don&#039;t enforce any schema and the result is considered to be just text.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following example configures the script&#039;s return value to contain an object having five different types of properties.:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;string&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;String parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;number&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;number&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Number parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;boolean&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;boolean&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Boolean parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;array&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Array parameter&amp;quot;,&lt;br /&gt;
        &amp;quot;nullable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;items&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;object&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Object parameter&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;inner&amp;quot;: {&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;}&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing MCP tools in QPR ProcessAnalyzer ==&lt;br /&gt;
When developing MCP tools, it might be useful try test them in QPR ProcessAnalyzer before publishing as MCP tools. Scripts (used as MCP tools) can be called in the [[Navigation_Menu#Expression_Designer|Expression Designer]]. The following example expression calls a script with some parameters and shows the return value as json:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot; line&amp;gt;&lt;br /&gt;
let returnValue = ScriptById(1).Run(#{&lt;br /&gt;
  &amp;quot;string_param&amp;quot;: &amp;quot;value1&amp;quot;,&lt;br /&gt;
  &amp;quot;integer_param&amp;quot;: 123,&lt;br /&gt;
  &amp;quot;boolean_param&amp;quot;: false,&lt;br /&gt;
  &amp;quot;array_param&amp;quot;: [&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;]&lt;br /&gt;
});&lt;br /&gt;
return ToJson(returnValue);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_CONFIGURATION database table.&lt;br /&gt;
* &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_CONFIGURATION database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)]. This is often automatically done by MCP Client software.&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
* Connect to Server: &lt;br /&gt;
** In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., https://your-pa-server/qprpa/api/mcp)&lt;br /&gt;
** Select Streamable HTTP as the transport type.&lt;br /&gt;
** Select &amp;quot;Via Proxy&amp;quot; as connection type.&lt;br /&gt;
* Authenticate: &lt;br /&gt;
** If using API Key-based authentication, configure &amp;quot;X-Mcp-Api-Key&amp;quot; as additional custom header with the value specified in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting of the PA server.&lt;br /&gt;
** If using OAuth, set one of the accepted audience values to Authentication/OAuth 2.0 Flow/Client ID (or leave it empty if DCR is enabled).&lt;br /&gt;
*** Open Auth Settings&lt;br /&gt;
*** Click &amp;quot;Quick OAuth Flow&amp;quot;-button.&lt;br /&gt;
**** Perform OAuth authorization using the built-in OAuth provider.&lt;br /&gt;
**** Provided that the authentication has been configured correctly, a successful authentication message should be shown.&lt;br /&gt;
** Click Connect.&lt;br /&gt;
* List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool created for a parameterless QPR ProcessAnalyzer script having id 216, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
  &amp;quot;params&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Script-216&amp;quot;,&lt;br /&gt;
    &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
    &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
      &amp;quot;progressToken&amp;quot;: 0&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28185</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28185"/>
		<updated>2026-04-27T10:50:09Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-64041&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API key. Both the authentication methods can be configured at the same time to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication, set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_CONFIGURATION database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
Some clients use the [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint: /.well-known/openid-configuration. To get this endpoint working when QPR ProcessAnalyzer is hosted in Windows in IIS, the following setup is required:&lt;br /&gt;
&lt;br /&gt;
Add an IIS rewrite rule and a CORS header at the IIS root-level &#039;&#039;&#039;web.config&#039;&#039;&#039;. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
== Creating MCP Tools ==&lt;br /&gt;
MCP tools are implemented using [[Managing_Scripts|scripts]] written in QPR ProcessAnalyzer expression language. A script will be added as the MCP tool when the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox is enabled in the [[Managing_Scripts#Script_Properties|Script Properties]]. Only system administrator users can enable the MCP tool checkbox. Also, scripts that are MCP tools, only system administrators can modify them because any changes to the MCP interface is restricted to system administrators for security reasons.&lt;br /&gt;
&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# Open or create the script.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab and select the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;Description&#039;&#039;&#039; tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
=== Defining Input Parameters ===&lt;br /&gt;
MCP tool input parameters are defined using a JSON schema following the [https://modelcontextprotocol.io/specification/2025-11-25/basic#json-schema-usage Model Context Protocol&#039;s JSON Schema]. Each supported input parameter is listed under &#039;&#039;&#039;properties&#039;&#039;&#039;. By default, script don&#039;t enforce any schema.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following schema defines one required string parameter named &#039;&#039;&#039;CaseId&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;CaseId&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
      &amp;quot;minLength&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;Unique identifier of the case (i.e, Case ID). Cases may be orders, deliveries, invoices depending on the model name.&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following schema defines an integer parameter named &#039;&#039;&#039;modelId&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;modelId&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;Model ID (identifier)&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When a tool is called, input is validated against the configured parameter schema. Validation is performed against the sanitized parameter collection so that empty or omitted parameter sets are handled consistently.&lt;br /&gt;
&lt;br /&gt;
=== Defining Structured Tool Output ===&lt;br /&gt;
Structured tool output is described using a JSON schema following the [https://modelcontextprotocol.io/specification/2025-11-25/basic#json-schema-usage Model Context Protocol&#039;s JSON Schema]. By default, scripts don&#039;t enforce any schema and the result is considered to be just text.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following example configures the script&#039;s return value to contain an object having five different types of properties.:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;string&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;String parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;number&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;number&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Number parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;boolean&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;boolean&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Boolean parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;array&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Array parameter&amp;quot;,&lt;br /&gt;
        &amp;quot;nullable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;items&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;object&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Object parameter&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;inner&amp;quot;: {&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;}&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing MCP tools in QPR ProcessAnalyzer ==&lt;br /&gt;
When developing MCP tools, it might be useful try test them in QPR ProcessAnalyzer before publishing as MCP tools. Scripts (used as MCP tools) can be called in the [[Navigation_Menu#Expression_Designer|Expression Designer]]. The following example expression calls a script with some parameters and shows the return value as json:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot; line&amp;gt;&lt;br /&gt;
let returnValue = ScriptById(1).Run(#{&lt;br /&gt;
  &amp;quot;string_param&amp;quot;: &amp;quot;value1&amp;quot;,&lt;br /&gt;
  &amp;quot;integer_param&amp;quot;: 123,&lt;br /&gt;
  &amp;quot;boolean_param&amp;quot;: false,&lt;br /&gt;
  &amp;quot;array_param&amp;quot;: [&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;]&lt;br /&gt;
});&lt;br /&gt;
return ToJson(returnValue);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_CONFIGURATION database table.&lt;br /&gt;
* &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_CONFIGURATION database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)]. This is often automatically done by MCP Client software.&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
* Connect to Server: &lt;br /&gt;
** In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., https://your-pa-server/qprpa/api/mcp)&lt;br /&gt;
** Select Streamable HTTP as the transport type.&lt;br /&gt;
** Select &amp;quot;Via Proxy&amp;quot; as connection type.&lt;br /&gt;
* Authenticate: &lt;br /&gt;
** If using API Key-based authentication, configure &amp;quot;X-Mcp-Api-Key&amp;quot; as additional custom header with the value specified in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting of the PA server.&lt;br /&gt;
** If using OAuth, set one of the accepted audience values to Authentication/OAuth 2.0 Flow/Client ID (or leave it empty if DCR is enabled).&lt;br /&gt;
*** Open Auth Settings&lt;br /&gt;
*** Click &amp;quot;Quick OAuth Flow&amp;quot;-button.&lt;br /&gt;
**** Perform OAuth authorization using the built-in OAuth provider.&lt;br /&gt;
**** Provided that the authentication has been configured correctly, a successful authentication message should be shown.&lt;br /&gt;
** Click Connect.&lt;br /&gt;
* List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool created for a parameterless QPR ProcessAnalyzer script having id 216, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
  &amp;quot;params&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Script-216&amp;quot;,&lt;br /&gt;
    &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
    &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
      &amp;quot;progressToken&amp;quot;: 0&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28184</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28184"/>
		<updated>2026-04-27T10:48:09Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-64041&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API key. Both the authentication methods can be configured at the same time to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication, set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_CONFIGURATION database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
Some clients use the [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint: /.well-known/openid-configuration. To get this endpoint working when QPR ProcessAnalyzer is hosted in Windows in IIS, the following setup is required:&lt;br /&gt;
&lt;br /&gt;
Add an IIS rewrite rule and a CORS header at the IIS root-level &#039;&#039;&#039;web.config&#039;&#039;&#039;. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
== Creating MCP Tools ==&lt;br /&gt;
MCP tools are implemented using [[Managing_Scripts|scripts]] written in QPR ProcessAnalyzer expression language. A script will be added as the MCP tool when the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox is enabled in the [[Managing_Scripts#Script_Properties|Script Properties]]. Only system administrator users can enable the MCP tool checkbox. Also, scripts that are MCP tools, only system administrators can modify them because any changes to the MCP interface is restricted to system administrators for security reasons.&lt;br /&gt;
&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# Open or create the script.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab and select the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;Description&#039;&#039;&#039; tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
== Defining Input Parameters ==&lt;br /&gt;
MCP tool input parameters are defined using a JSON schema following the [https://modelcontextprotocol.io/specification/2025-11-25/basic#json-schema-usage Model Context Protocol&#039;s JSON Schema]. Each supported input parameter is listed under &#039;&#039;&#039;properties&#039;&#039;&#039;. By default, script don&#039;t enforce any schema.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following schema defines one required string parameter named &#039;&#039;&#039;CaseId&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;CaseId&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
      &amp;quot;minLength&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;Unique identifier of the case (i.e, Case ID). Cases may be orders, deliveries, invoices depending on the model name.&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following schema defines an integer parameter named &#039;&#039;&#039;modelId&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;modelId&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;Model ID (identifier)&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When a tool is called, input is validated against the configured parameter schema. Validation is performed against the sanitized parameter collection so that empty or omitted parameter sets are handled consistently.&lt;br /&gt;
&lt;br /&gt;
== Defining Structured Tool Output ==&lt;br /&gt;
Structured tool output is described using a JSON schema following the [https://modelcontextprotocol.io/specification/2025-11-25/basic#json-schema-usage Model Context Protocol&#039;s JSON Schema]. By default, scripts don&#039;t enforce any schema and the result is considered to be just text.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following example configures the script&#039;s return value to contain an object having five different types of properties.:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;string&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;String parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;number&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;number&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Number parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;boolean&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;boolean&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Boolean parameter&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;array&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Array parameter&amp;quot;,&lt;br /&gt;
        &amp;quot;nullable&amp;quot;: true,&lt;br /&gt;
        &amp;quot;items&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;object&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Object parameter&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;inner&amp;quot;: {&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;}&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing MCP tools in QPR ProcessAnalyzer ==&lt;br /&gt;
When developing MCP tools, it might be useful try test them in QPR ProcessAnalyzer before publishing as MCP tools. Scripts (used as MCP tools) can be called in the [[Navigation_Menu#Expression_Designer|Expression Designer]]. The following example expression calls a script with some parameters and shows the return value as json:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot; line&amp;gt;&lt;br /&gt;
let returnValue = ScriptById(1).Run(#{&lt;br /&gt;
  &amp;quot;string_param&amp;quot;: &amp;quot;value1&amp;quot;,&lt;br /&gt;
  &amp;quot;integer_param&amp;quot;: 123,&lt;br /&gt;
  &amp;quot;boolean_param&amp;quot;: false,&lt;br /&gt;
  &amp;quot;array_param&amp;quot;: [&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;]&lt;br /&gt;
});&lt;br /&gt;
return ToJson(returnValue);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_CONFIGURATION database table.&lt;br /&gt;
* &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_CONFIGURATION database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)]. This is often automatically done by MCP Client software.&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
* Connect to Server: &lt;br /&gt;
** In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., https://your-pa-server/qprpa/api/mcp)&lt;br /&gt;
** Select Streamable HTTP as the transport type.&lt;br /&gt;
** Select &amp;quot;Via Proxy&amp;quot; as connection type.&lt;br /&gt;
* Authenticate: &lt;br /&gt;
** If using API Key-based authentication, configure &amp;quot;X-Mcp-Api-Key&amp;quot; as additional custom header with the value specified in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting of the PA server.&lt;br /&gt;
** If using OAuth, set one of the accepted audience values to Authentication/OAuth 2.0 Flow/Client ID (or leave it empty if DCR is enabled).&lt;br /&gt;
*** Open Auth Settings&lt;br /&gt;
*** Click &amp;quot;Quick OAuth Flow&amp;quot;-button.&lt;br /&gt;
**** Perform OAuth authorization using the built-in OAuth provider.&lt;br /&gt;
**** Provided that the authentication has been configured correctly, a successful authentication message should be shown.&lt;br /&gt;
** Click Connect.&lt;br /&gt;
* List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool created for a parameterless QPR ProcessAnalyzer script having id 216, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
  &amp;quot;params&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Script-216&amp;quot;,&lt;br /&gt;
    &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
    &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
      &amp;quot;progressToken&amp;quot;: 0&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28183</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28183"/>
		<updated>2026-04-27T10:41:28Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-64041&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API key. Both the authentication methods can be configured at the same time to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication, set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_CONFIGURATION database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
Some clients use the [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint: /.well-known/openid-configuration. To get this endpoint working when QPR ProcessAnalyzer is hosted in Windows in IIS, the following setup is required:&lt;br /&gt;
&lt;br /&gt;
Add an IIS rewrite rule and a CORS header at the IIS root-level &#039;&#039;&#039;web.config&#039;&#039;&#039;. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
== Creating MCP Tools ==&lt;br /&gt;
MCP tools are implemented using [[Managing_Scripts|scripts]] written in QPR ProcessAnalyzer expression language. A script will be added as the MCP tool when the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox is enabled in the [[Managing_Scripts#Script_Properties|Script Properties]]. Only system administrator users can enable the MCP tool checkbox. Also, scripts that are MCP tools, only system administrators can modify them because any changes to the MCP interface is restricted to system administrators for security reasons.&lt;br /&gt;
&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# Open or create the script.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab and select the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;Description&#039;&#039;&#039; tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
== Defining Input Parameters ==&lt;br /&gt;
MCP tool input parameters are defined using a JSON schema following the [https://modelcontextprotocol.io/specification/2025-11-25/basic#json-schema-usage Model Context Protocol&#039;s JSON Schema]. Each supported input parameter is listed under &#039;&#039;&#039;properties&#039;&#039;&#039;. By default, script don&#039;t enforce any schema.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following schema defines one required string parameter named &#039;&#039;&#039;CaseId&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;CaseId&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
      &amp;quot;minLength&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;Unique identifier of the case (i.e, Case ID). Cases may be orders, deliveries, invoices depending on the model name.&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following schema defines an integer parameter named &#039;&#039;&#039;modelId&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;modelId&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;Model ID (identifier)&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When a tool is called, input is validated against the configured parameter schema. Validation is performed against the sanitized parameter collection so that empty or omitted parameter sets are handled consistently.&lt;br /&gt;
&lt;br /&gt;
== Defining Structured Tool Output ==&lt;br /&gt;
Structured tool output is described using a JSON schema. This allows the MCP client to interpret the response as structured data instead of only plain text. The schema is defined as part of the MCP tool configuration, and the script should return data that matches the configured structure.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following example defines an object containing a &#039;&#039;&#039;filters&#039;&#039;&#039; array. Each array item is an object with named properties:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;filters&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;List of defined filters in the given model (as parameter).&amp;quot;,&lt;br /&gt;
      &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: {&lt;br /&gt;
          &amp;quot;Filter name&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Human-readable name of the filter.&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;Filter ID&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Unique identifier of the filter.&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;Privacy mode&amp;quot;: {&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&lt;br /&gt;
              &amp;quot;Default Public&amp;quot;,&lt;br /&gt;
              &amp;quot;Public&amp;quot;,&lt;br /&gt;
              &amp;quot;Private&amp;quot;&lt;br /&gt;
            ],&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Visibility and access level of the filter.&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;Filter description&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Optional free-text description explaining the purpose and intended use of the filter.&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;Filter rules&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Filter definition expressed in JSON format. The rules specify the exact criteria used to include or exclude data.&amp;quot;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing MCP tools in QPR ProcessAnalyzer ==&lt;br /&gt;
When developing MCP tools, it might be useful try test them in QPR ProcessAnalyzer before publishing as MCP tools. Scripts (used as MCP tools) can be called in the [[Navigation_Menu#Expression_Designer|Expression Designer]]. The following example expression calls a script with some parameters and shows the return value as json:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot; line&amp;gt;&lt;br /&gt;
let returnValue = ScriptById(1).Run(#{&lt;br /&gt;
  &amp;quot;string_param&amp;quot;: &amp;quot;value1&amp;quot;,&lt;br /&gt;
  &amp;quot;integer_param&amp;quot;: 123,&lt;br /&gt;
  &amp;quot;boolean_param&amp;quot;: false,&lt;br /&gt;
  &amp;quot;array_param&amp;quot;: [&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;]&lt;br /&gt;
});&lt;br /&gt;
return ToJson(returnValue);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_CONFIGURATION database table.&lt;br /&gt;
* &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_CONFIGURATION database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)]. This is often automatically done by MCP Client software.&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
* Connect to Server: &lt;br /&gt;
** In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., https://your-pa-server/qprpa/api/mcp)&lt;br /&gt;
** Select Streamable HTTP as the transport type.&lt;br /&gt;
** Select &amp;quot;Via Proxy&amp;quot; as connection type.&lt;br /&gt;
* Authenticate: &lt;br /&gt;
** If using API Key-based authentication, configure &amp;quot;X-Mcp-Api-Key&amp;quot; as additional custom header with the value specified in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting of the PA server.&lt;br /&gt;
** If using OAuth, set one of the accepted audience values to Authentication/OAuth 2.0 Flow/Client ID (or leave it empty if DCR is enabled).&lt;br /&gt;
*** Open Auth Settings&lt;br /&gt;
*** Click &amp;quot;Quick OAuth Flow&amp;quot;-button.&lt;br /&gt;
**** Perform OAuth authorization using the built-in OAuth provider.&lt;br /&gt;
**** Provided that the authentication has been configured correctly, a successful authentication message should be shown.&lt;br /&gt;
** Click Connect.&lt;br /&gt;
* List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool created for a parameterless QPR ProcessAnalyzer script having id 216, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
  &amp;quot;params&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Script-216&amp;quot;,&lt;br /&gt;
    &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
    &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
      &amp;quot;progressToken&amp;quot;: 0&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28182</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28182"/>
		<updated>2026-04-27T10:41:08Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-64041&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API key. Both the authentication methods can be configured at the same time to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication, set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_CONFIGURATION database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
Some clients use the [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint: /.well-known/openid-configuration. To get this endpoint working when QPR ProcessAnalyzer is hosted in Windows in IIS, the following setup is required:&lt;br /&gt;
&lt;br /&gt;
Add an IIS rewrite rule and a CORS header at the IIS root-level &#039;&#039;&#039;web.config&#039;&#039;&#039;. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
== Creating MCP Tools ==&lt;br /&gt;
MCP tools are implemented using [[Managing_Scripts|scripts]] written in QPR ProcessAnalyzer expression language. A script will be added as the MCP tool when the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox is enabled in the [[Managing_Scripts#Script_Properties|Script Properties]]. Only system administrator users can enable the MCP tool checkbox. Also, scripts that are MCP tools, only system administrators can modify them because any changes to the MCP interface is restricted to system administrators for security reasons.&lt;br /&gt;
&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# Open or create the script.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab and select the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;Description&#039;&#039;&#039; tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
== Defining Input Parameters ==&lt;br /&gt;
MCP tool input parameters are defined using a JSON schema following the [https://modelcontextprotocol.io/specification/2025-11-25/basic#json-schema-usage Model Context Protocol&#039;s JSON Schema]. Each supported input parameter is listed under &#039;&#039;&#039;properties&#039;&#039;&#039;. By default, script don&#039;t enforce any schema.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following schema defines one required string parameter named &#039;&#039;&#039;CaseId&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;CaseId&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
      &amp;quot;minLength&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;Unique identifier of the case (i.e, Case ID). Cases may be orders, deliveries, invoices depending on the model name.&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following schema defines an integer parameter named &#039;&#039;&#039;modelId&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;modelId&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;Model ID (identifier)&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When a tool is called, input is validated against the configured parameter schema. Validation is performed against the sanitized parameter collection so that empty or omitted parameter sets are handled consistently.&lt;br /&gt;
&lt;br /&gt;
== Defining Structured Tool Output ==&lt;br /&gt;
Structured tool output is described using a JSON schema. This allows the MCP client to interpret the response as structured data instead of only plain text. The schema is defined as part of the MCP tool configuration, and the script should return data that matches the configured structure.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following example defines an object containing a &#039;&#039;&#039;filters&#039;&#039;&#039; array. Each array item is an object with named properties:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;filters&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;List of defined filters in the given model (as parameter).&amp;quot;,&lt;br /&gt;
      &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: {&lt;br /&gt;
          &amp;quot;Filter name&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Human-readable name of the filter.&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;Filter ID&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Unique identifier of the filter.&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;Privacy mode&amp;quot;: {&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&lt;br /&gt;
              &amp;quot;Default Public&amp;quot;,&lt;br /&gt;
              &amp;quot;Public&amp;quot;,&lt;br /&gt;
              &amp;quot;Private&amp;quot;&lt;br /&gt;
            ],&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Visibility and access level of the filter.&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;Filter description&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Optional free-text description explaining the purpose and intended use of the filter.&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;Filter rules&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Filter definition expressed in JSON format. The rules specify the exact criteria used to include or exclude data.&amp;quot;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing MCP tools in QPR ProcessAnalyzer ==&lt;br /&gt;
When developing MCP tools, it might be useful try test them in QPR ProcessAnalyzer before publishing as MCP tools. Scripts (used as MCP tools) can be called in the [[Navigation_Menu#Expression_Designer|Expression Designer]]. The following example expression calls a script with some parameters and shows the return value as json:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot; line&amp;gt;&lt;br /&gt;
let returnValue = ScriptById(1).Run(#{&lt;br /&gt;
  &amp;quot;string_param&amp;quot;: &amp;quot;value1&amp;quot;,&lt;br /&gt;
  &amp;quot;integer_param&amp;quot;: 123,&lt;br /&gt;
  &amp;quot;boolean_param&amp;quot;: false,&lt;br /&gt;
  &amp;quot;array_param&amp;quot;: [&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;]&lt;br /&gt;
});&lt;br /&gt;
return ToJson(returnValue);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_CONFIGURATION database table.&lt;br /&gt;
* &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_CONFIGURATION database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)]. This is often automatically done by MCP Client software.&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
* Connect to Server: &lt;br /&gt;
** In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., https://your-pa-server/qprpa/api/mcp)&lt;br /&gt;
** Select Streamable HTTP as the transport type.&lt;br /&gt;
** Select &amp;quot;Via Proxy&amp;quot; as connection type.&lt;br /&gt;
* Authenticate: &lt;br /&gt;
** If using API Key-based authentication, configure &amp;quot;X-Mcp-Api-Key&amp;quot; as additional custom header with the value specified in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting of the PA server.&lt;br /&gt;
** If using OAuth, set one of the accepted audience values to Authentication/OAuth 2.0 Flow/Client ID (or leave it empty if DCR is enabled).&lt;br /&gt;
*** Open Auth Settings&lt;br /&gt;
*** Click &amp;quot;Quick OAuth Flow&amp;quot;-button.&lt;br /&gt;
**** Perform OAuth authorization using the built-in OAuth provider.&lt;br /&gt;
**** Provided that the authentication has been configured correctly, a successful authentication message should be shown.&lt;br /&gt;
** Click Connect.&lt;br /&gt;
* List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool created for a parameterless QPR ProcessAnalyzer script having id 216, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
  &amp;quot;params&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Script-216&amp;quot;,&lt;br /&gt;
    &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
    &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
      &amp;quot;progressToken&amp;quot;: 0&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28181</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28181"/>
		<updated>2026-04-27T10:40:25Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-64041&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API key. Both the authentication methods can be configured at the same time to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication, set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_CONFIGURATION database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
Some clients use the [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint: /.well-known/openid-configuration. To get this endpoint working when QPR ProcessAnalyzer is hosted in Windows in IIS, the following setup is required:&lt;br /&gt;
&lt;br /&gt;
Add an IIS rewrite rule and a CORS header at the IIS root-level &#039;&#039;&#039;web.config&#039;&#039;&#039;. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
== Creating MCP Tools ==&lt;br /&gt;
MCP tools are implemented using [[Managing_Scripts|scripts]] written in QPR ProcessAnalyzer expression language. A script will be added as the MCP tool when the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox is enabled in the [[Managing_Scripts#Script_Properties|Script Properties]]. Only system administrator users can enable the MCP tool checkbox. Also, scripts that are MCP tools, only system administrators can modify them because any changes to the MCP interface is restricted to system administrators for security reasons.&lt;br /&gt;
&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# Open or create the script.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab and select the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;Description&#039;&#039;&#039; tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
== Defining Input Parameters ==&lt;br /&gt;
MCP tool input parameters are defined using a JSON schema following the [https://modelcontextprotocol.io/specification/2025-11-25/basic#json-schema-usage Model Context Protocol&#039;s JSON Schema]. Each supported input parameter is listed under &#039;&#039;&#039;properties&#039;&#039;&#039;. By default, script don&#039;t enforce any schema.&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following schema defines one required string parameter named &#039;&#039;&#039;CaseId&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;additionalProperties&amp;quot;: false,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;CaseId&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
      &amp;quot;minLength&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;Unique identifier of the case (i.e, Case ID). Cases may be orders, deliveries, invoices depending on the model name.&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following schema defines an integer parameter named &#039;&#039;&#039;modelId&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;additionalProperties&amp;quot;: false,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;modelId&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;Model ID (identifier)&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When a tool is called, input is validated against the configured parameter schema. Validation is performed against the sanitized parameter collection so that empty or omitted parameter sets are handled consistently.&lt;br /&gt;
&lt;br /&gt;
== Defining Structured Tool Output ==&lt;br /&gt;
Structured tool output is described using a JSON schema. This allows the MCP client to interpret the response as structured data instead of only plain text. The schema is defined as part of the MCP tool configuration, and the script should return data that matches the configured structure.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following example defines an object containing a &#039;&#039;&#039;filters&#039;&#039;&#039; array. Each array item is an object with named properties:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;filters&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;List of defined filters in the given model (as parameter).&amp;quot;,&lt;br /&gt;
      &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: {&lt;br /&gt;
          &amp;quot;Filter name&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Human-readable name of the filter.&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;Filter ID&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Unique identifier of the filter.&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;Privacy mode&amp;quot;: {&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&lt;br /&gt;
              &amp;quot;Default Public&amp;quot;,&lt;br /&gt;
              &amp;quot;Public&amp;quot;,&lt;br /&gt;
              &amp;quot;Private&amp;quot;&lt;br /&gt;
            ],&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Visibility and access level of the filter.&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;Filter description&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Optional free-text description explaining the purpose and intended use of the filter.&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;Filter rules&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Filter definition expressed in JSON format. The rules specify the exact criteria used to include or exclude data.&amp;quot;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing MCP tools in QPR ProcessAnalyzer ==&lt;br /&gt;
When developing MCP tools, it might be useful try test them in QPR ProcessAnalyzer before publishing as MCP tools. Scripts (used as MCP tools) can be called in the [[Navigation_Menu#Expression_Designer|Expression Designer]]. The following example expression calls a script with some parameters and shows the return value as json:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot; line&amp;gt;&lt;br /&gt;
let returnValue = ScriptById(1).Run(#{&lt;br /&gt;
  &amp;quot;string_param&amp;quot;: &amp;quot;value1&amp;quot;,&lt;br /&gt;
  &amp;quot;integer_param&amp;quot;: 123,&lt;br /&gt;
  &amp;quot;boolean_param&amp;quot;: false,&lt;br /&gt;
  &amp;quot;array_param&amp;quot;: [&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;]&lt;br /&gt;
});&lt;br /&gt;
return ToJson(returnValue);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_CONFIGURATION database table.&lt;br /&gt;
* &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_CONFIGURATION database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)]. This is often automatically done by MCP Client software.&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
* Connect to Server: &lt;br /&gt;
** In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., https://your-pa-server/qprpa/api/mcp)&lt;br /&gt;
** Select Streamable HTTP as the transport type.&lt;br /&gt;
** Select &amp;quot;Via Proxy&amp;quot; as connection type.&lt;br /&gt;
* Authenticate: &lt;br /&gt;
** If using API Key-based authentication, configure &amp;quot;X-Mcp-Api-Key&amp;quot; as additional custom header with the value specified in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting of the PA server.&lt;br /&gt;
** If using OAuth, set one of the accepted audience values to Authentication/OAuth 2.0 Flow/Client ID (or leave it empty if DCR is enabled).&lt;br /&gt;
*** Open Auth Settings&lt;br /&gt;
*** Click &amp;quot;Quick OAuth Flow&amp;quot;-button.&lt;br /&gt;
**** Perform OAuth authorization using the built-in OAuth provider.&lt;br /&gt;
**** Provided that the authentication has been configured correctly, a successful authentication message should be shown.&lt;br /&gt;
** Click Connect.&lt;br /&gt;
* List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool created for a parameterless QPR ProcessAnalyzer script having id 216, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
  &amp;quot;params&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Script-216&amp;quot;,&lt;br /&gt;
    &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
    &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
      &amp;quot;progressToken&amp;quot;: 0&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28180</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28180"/>
		<updated>2026-04-27T10:34:04Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-64041&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API key. Both the authentication methods can be configured at the same time to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication, set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_CONFIGURATION database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
Some clients use the [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint: /.well-known/openid-configuration. To get this endpoint working when QPR ProcessAnalyzer is hosted in Windows in IIS, the following setup is required:&lt;br /&gt;
&lt;br /&gt;
Add an IIS rewrite rule and a CORS header at the IIS root-level &#039;&#039;&#039;web.config&#039;&#039;&#039;. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
== Creating MCP Tools ==&lt;br /&gt;
MCP tools are implemented using [[Managing_Scripts|scripts]] written in QPR ProcessAnalyzer expression language. A script will be added as the MCP tool when the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox is enabled in the [[Managing_Scripts#Script_Properties|Script Properties]]. Only system administrator users can enable the MCP tool checkbox. Also, scripts that are MCP tools, only system administrators can modify them because any changes to the MCP interface is restricted to system administrators for security reasons.&lt;br /&gt;
&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# Open or create the script.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab and select the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;Description&#039;&#039;&#039; tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
== Defining Input Parameters ==&lt;br /&gt;
MCP tool input parameters are defined using a JSON schema where each supported input parameter is listed under &#039;&#039;&#039;properties&#039;&#039;&#039;, and &#039;&#039;&#039;additionalProperties&#039;&#039;&#039; can be set to false to reject unknown parameters.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following schema defines one required string parameter named &#039;&#039;&#039;CaseId&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;additionalProperties&amp;quot;: false,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;CaseId&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
      &amp;quot;minLength&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;Unique identifier of the case (i.e, Case ID). Cases may be orders, deliveries, invoices depending on the model name.&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following schema defines an integer parameter named &#039;&#039;&#039;modelId&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;additionalProperties&amp;quot;: false,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;modelId&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;Model ID (identifier)&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When a tool is called, input is validated against the configured parameter schema. Validation is performed against the sanitized parameter collection so that empty or omitted parameter sets are handled consistently.&lt;br /&gt;
&lt;br /&gt;
== Defining Structured Tool Output ==&lt;br /&gt;
Structured tool output is described using a JSON schema. This allows the MCP client to interpret the response as structured data instead of only plain text. The schema is defined as part of the MCP tool configuration, and the script should return data that matches the configured structure.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following example defines an object containing a &#039;&#039;&#039;filters&#039;&#039;&#039; array. Each array item is an object with named properties:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;filters&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;List of defined filters in the given model (as parameter).&amp;quot;,&lt;br /&gt;
      &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: {&lt;br /&gt;
          &amp;quot;Filter name&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Human-readable name of the filter.&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;Filter ID&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Unique identifier of the filter.&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;Privacy mode&amp;quot;: {&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&lt;br /&gt;
              &amp;quot;Default Public&amp;quot;,&lt;br /&gt;
              &amp;quot;Public&amp;quot;,&lt;br /&gt;
              &amp;quot;Private&amp;quot;&lt;br /&gt;
            ],&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Visibility and access level of the filter.&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;Filter description&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Optional free-text description explaining the purpose and intended use of the filter.&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;Filter rules&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Filter definition expressed in JSON format. The rules specify the exact criteria used to include or exclude data.&amp;quot;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing MCP tools in QPR ProcessAnalyzer ==&lt;br /&gt;
When developing MCP tools, it might be useful try test them in QPR ProcessAnalyzer before publishing as MCP tools. Scripts (used as MCP tools) can be called in the [[Navigation_Menu#Expression_Designer|Expression Designer]]. The following example expression calls a script with some parameters and shows the return value as json:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot; line&amp;gt;&lt;br /&gt;
let returnValue = ScriptById(1).Run(#{&lt;br /&gt;
  &amp;quot;string_param&amp;quot;: &amp;quot;value1&amp;quot;,&lt;br /&gt;
  &amp;quot;integer_param&amp;quot;: 123,&lt;br /&gt;
  &amp;quot;boolean_param&amp;quot;: false,&lt;br /&gt;
  &amp;quot;array_param&amp;quot;: [&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;]&lt;br /&gt;
});&lt;br /&gt;
return ToJson(returnValue);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_CONFIGURATION database table.&lt;br /&gt;
* &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_CONFIGURATION database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)]. This is often automatically done by MCP Client software.&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
* Connect to Server: &lt;br /&gt;
** In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., https://your-pa-server/qprpa/api/mcp)&lt;br /&gt;
** Select Streamable HTTP as the transport type.&lt;br /&gt;
** Select &amp;quot;Via Proxy&amp;quot; as connection type.&lt;br /&gt;
* Authenticate: &lt;br /&gt;
** If using API Key-based authentication, configure &amp;quot;X-Mcp-Api-Key&amp;quot; as additional custom header with the value specified in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting of the PA server.&lt;br /&gt;
** If using OAuth, set one of the accepted audience values to Authentication/OAuth 2.0 Flow/Client ID (or leave it empty if DCR is enabled).&lt;br /&gt;
*** Open Auth Settings&lt;br /&gt;
*** Click &amp;quot;Quick OAuth Flow&amp;quot;-button.&lt;br /&gt;
**** Perform OAuth authorization using the built-in OAuth provider.&lt;br /&gt;
**** Provided that the authentication has been configured correctly, a successful authentication message should be shown.&lt;br /&gt;
** Click Connect.&lt;br /&gt;
* List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool created for a parameterless QPR ProcessAnalyzer script having id 216, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
  &amp;quot;params&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Script-216&amp;quot;,&lt;br /&gt;
    &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
    &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
      &amp;quot;progressToken&amp;quot;: 0&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28179</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28179"/>
		<updated>2026-04-27T10:33:28Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-64041&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API key. Both the authentication methods can be configured at the same time to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication, set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_CONFIGURATION database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
Some clients use the [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint: /.well-known/openid-configuration. To get this endpoint working when QPR ProcessAnalyzer is hosted in Windows in IIS, the following setup is required:&lt;br /&gt;
&lt;br /&gt;
Add an IIS rewrite rule and a CORS header at the IIS root-level &#039;&#039;&#039;web.config&#039;&#039;&#039;. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
== Creating MCP Tools ==&lt;br /&gt;
MCP tools are implemented using [[Managing_Scripts|scripts]] written in QPR ProcessAnalyzer expression language. A script will be added as the MCP tool when the **MCP tool** checkbox is enabled in the [[Managing_Scripts#Script_Properties|Script Properties]]. Only system administrator users can enable the MCP tool checkbox. Also, scripts that are MCP tools, only system administrators can modify them because any changes to the MCP interface is restricted to system administrators for security reasons.&lt;br /&gt;
&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# Open or create the script.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab and select the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;Description&#039;&#039;&#039; tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
== Defining Input Parameters ==&lt;br /&gt;
MCP tool input parameters are defined using a JSON schema where each supported input parameter is listed under &#039;&#039;&#039;properties&#039;&#039;&#039;, and &#039;&#039;&#039;additionalProperties&#039;&#039;&#039; can be set to false to reject unknown parameters.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following schema defines one required string parameter named &#039;&#039;&#039;CaseId&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;additionalProperties&amp;quot;: false,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;CaseId&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
      &amp;quot;minLength&amp;quot;: 1,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;Unique identifier of the case (i.e, Case ID). Cases may be orders, deliveries, invoices depending on the model name.&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following schema defines an integer parameter named &#039;&#039;&#039;modelId&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;additionalProperties&amp;quot;: false,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;modelId&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;Model ID (identifier)&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When a tool is called, input is validated against the configured parameter schema. Validation is performed against the sanitized parameter collection so that empty or omitted parameter sets are handled consistently.&lt;br /&gt;
&lt;br /&gt;
== Defining Structured Tool Output ==&lt;br /&gt;
Structured tool output is described using a JSON schema. This allows the MCP client to interpret the response as structured data instead of only plain text. The schema is defined as part of the MCP tool configuration, and the script should return data that matches the configured structure.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;: The following example defines an object containing a &#039;&#039;&#039;filters&#039;&#039;&#039; array. Each array item is an object with named properties:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
  &amp;quot;properties&amp;quot;: {&lt;br /&gt;
    &amp;quot;filters&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;List of defined filters in the given model (as parameter).&amp;quot;,&lt;br /&gt;
      &amp;quot;items&amp;quot;: {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
        &amp;quot;properties&amp;quot;: {&lt;br /&gt;
          &amp;quot;Filter name&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Human-readable name of the filter.&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;Filter ID&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Unique identifier of the filter.&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;Privacy mode&amp;quot;: {&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&lt;br /&gt;
              &amp;quot;Default Public&amp;quot;,&lt;br /&gt;
              &amp;quot;Public&amp;quot;,&lt;br /&gt;
              &amp;quot;Private&amp;quot;&lt;br /&gt;
            ],&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Visibility and access level of the filter.&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;Filter description&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Optional free-text description explaining the purpose and intended use of the filter.&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
          &amp;quot;Filter rules&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Filter definition expressed in JSON format. The rules specify the exact criteria used to include or exclude data.&amp;quot;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing MCP tools in QPR ProcessAnalyzer ==&lt;br /&gt;
When developing MCP tools, it might be useful try test them in QPR ProcessAnalyzer before publishing as MCP tools. Scripts (used as MCP tools) can be called in the [[Navigation_Menu#Expression_Designer|Expression Designer]]. The following example expression calls a script with some parameters and shows the return value as json:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot; line&amp;gt;&lt;br /&gt;
let returnValue = ScriptById(1).Run(#{&lt;br /&gt;
  &amp;quot;string_param&amp;quot;: &amp;quot;value1&amp;quot;,&lt;br /&gt;
  &amp;quot;integer_param&amp;quot;: 123,&lt;br /&gt;
  &amp;quot;boolean_param&amp;quot;: false,&lt;br /&gt;
  &amp;quot;array_param&amp;quot;: [&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;]&lt;br /&gt;
});&lt;br /&gt;
return ToJson(returnValue);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_CONFIGURATION database table.&lt;br /&gt;
* &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_CONFIGURATION database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)]. This is often automatically done by MCP Client software.&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
* Connect to Server: &lt;br /&gt;
** In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., https://your-pa-server/qprpa/api/mcp)&lt;br /&gt;
** Select Streamable HTTP as the transport type.&lt;br /&gt;
** Select &amp;quot;Via Proxy&amp;quot; as connection type.&lt;br /&gt;
* Authenticate: &lt;br /&gt;
** If using API Key-based authentication, configure &amp;quot;X-Mcp-Api-Key&amp;quot; as additional custom header with the value specified in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting of the PA server.&lt;br /&gt;
** If using OAuth, set one of the accepted audience values to Authentication/OAuth 2.0 Flow/Client ID (or leave it empty if DCR is enabled).&lt;br /&gt;
*** Open Auth Settings&lt;br /&gt;
*** Click &amp;quot;Quick OAuth Flow&amp;quot;-button.&lt;br /&gt;
**** Perform OAuth authorization using the built-in OAuth provider.&lt;br /&gt;
**** Provided that the authentication has been configured correctly, a successful authentication message should be shown.&lt;br /&gt;
** Click Connect.&lt;br /&gt;
* List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool created for a parameterless QPR ProcessAnalyzer script having id 216, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
  &amp;quot;params&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Script-216&amp;quot;,&lt;br /&gt;
    &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
    &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
      &amp;quot;progressToken&amp;quot;: 0&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28178</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28178"/>
		<updated>2026-04-27T10:18:30Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-64041&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API key. Both the authentication methods can be configured at the same time to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication, set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_CONFIGURATION database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
Some clients use the [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint: /.well-known/openid-configuration. To get this endpoint working when QPR ProcessAnalyzer is hosted in Windows in IIS, the following setup is required:&lt;br /&gt;
&lt;br /&gt;
Add an IIS rewrite rule and a CORS header at the IIS root-level &#039;&#039;&#039;web.config&#039;&#039;&#039;. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
== Creating MCP Tools ==&lt;br /&gt;
MCP tools are implemented using [[Managing_Scripts|scripts]] written in QPR ProcessAnalyzer expression language. A script will be added as the MCP tool when the **MCP tool** checkbox is enabled in the [[Managing_Scripts#Script_Properties|Script Properties]]. Only system administrator users can enable the MCP tool checkbox. Also, scripts that are MCP tools, only system administrators can modify them because any changes to the MCP interface is restricted to system administrators for security reasons.&lt;br /&gt;
&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# Open or create the script.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab and select the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;Description&#039;&#039;&#039; tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
== Testing MCP tools in QPR ProcessAnalyzer ==&lt;br /&gt;
When developing MCP tools, it might be useful try test them in QPR ProcessAnalyzer before publishing as MCP tools. Scripts (used as MCP tools) can be called in the [[Navigation_Menu#Expression_Designer|Expression Designer]]. The following example expression calls a script with some parameters and shows the return value as json:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot; line&amp;gt;&lt;br /&gt;
let returnValue = ScriptById(1).Run(#{&lt;br /&gt;
  &amp;quot;string_param&amp;quot;: &amp;quot;value1&amp;quot;,&lt;br /&gt;
  &amp;quot;integer_param&amp;quot;: 123,&lt;br /&gt;
  &amp;quot;boolean_param&amp;quot;: false,&lt;br /&gt;
  &amp;quot;array_param&amp;quot;: [&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;]&lt;br /&gt;
});&lt;br /&gt;
return ToJson(returnValue);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_CONFIGURATION database table.&lt;br /&gt;
* &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_CONFIGURATION database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)]. This is often automatically done by MCP Client software.&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
* Connect to Server: &lt;br /&gt;
** In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., https://your-pa-server/qprpa/api/mcp)&lt;br /&gt;
** Select Streamable HTTP as the transport type.&lt;br /&gt;
** Select &amp;quot;Via Proxy&amp;quot; as connection type.&lt;br /&gt;
* Authenticate: &lt;br /&gt;
** If using API Key-based authentication, configure &amp;quot;X-Mcp-Api-Key&amp;quot; as additional custom header with the value specified in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting of the PA server.&lt;br /&gt;
** If using OAuth, set one of the accepted audience values to Authentication/OAuth 2.0 Flow/Client ID (or leave it empty if DCR is enabled).&lt;br /&gt;
*** Open Auth Settings&lt;br /&gt;
*** Click &amp;quot;Quick OAuth Flow&amp;quot;-button.&lt;br /&gt;
**** Perform OAuth authorization using the built-in OAuth provider.&lt;br /&gt;
**** Provided that the authentication has been configured correctly, a successful authentication message should be shown.&lt;br /&gt;
** Click Connect.&lt;br /&gt;
* List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool created for a parameterless QPR ProcessAnalyzer script having id 216, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
  &amp;quot;params&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Script-216&amp;quot;,&lt;br /&gt;
    &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
    &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
      &amp;quot;progressToken&amp;quot;: 0&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=Data_Schema_Dialog&amp;diff=28125</id>
		<title>Data Schema Dialog</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=Data_Schema_Dialog&amp;diff=28125"/>
		<updated>2026-04-16T13:35:18Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63602&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Data Schema dialog provides a visual way to manage your project&#039;s Snowflake datatables and the relationships (foreign keys) between them.&amp;lt;br&amp;gt;&lt;br /&gt;
The Data Schema dialog displays an entity-relationship (ER) diagram of your datatables and their relations. The ER diagram automatically arranges the datatables and relations for a clear overview. You cannot manually change the position of items.&lt;br /&gt;
&lt;br /&gt;
You can zoom in and out, and pan across the diagram to explore your data schema. The view is constrained to keep the diagram visible. Clicking on a datatable or a relation in the diagram will select it and open a corresponding details panel on the side, allowing you to view and edit its properties. Clicking on an empty area of the diagram will unselect any item and close the panel.&amp;lt;br&amp;gt;&lt;br /&gt;
If your project has no datatables to display, a message &amp;quot;Start by adding a datatable&amp;quot; will appear.&lt;br /&gt;
&lt;br /&gt;
Note that datatables stored in SQL Server or those used in an object-centric model (Objects, Events, EventToObject, ObjectToObject) are not displayed in this dialog.&lt;br /&gt;
&lt;br /&gt;
== Column Display ==&lt;br /&gt;
A dropdown menu allows you to control the level of detail shown for columns in the datatables. The following selections are available:&lt;br /&gt;
* &#039;&#039;&#039;Don&#039;t show columns&#039;&#039;&#039;: Hides all columns for a clean, high-level view.&lt;br /&gt;
* &#039;&#039;&#039;Show key and relation columns&#039;&#039;&#039;: Displays only primary keys, foreign keys, and the columns they target.&lt;br /&gt;
* &#039;&#039;&#039;Show all columns&#039;&#039;&#039;: Shows every column for all datatables in the diagram.&lt;br /&gt;
&lt;br /&gt;
== Permissions ==&lt;br /&gt;
Your ability to make changes is determined by your project permissions. If you lack GenericWrite permissions, all fields will be read-only, and buttons for creating new items will be hidden. Deleting datatables requires the DeleteModel permission.&lt;br /&gt;
&lt;br /&gt;
== Handling Invalid Relations ==&lt;br /&gt;
When the dialog opens, it checks for invalid relations (e.g., a relation pointing to a non-existent datatable or column). If any are found, an error message will appear with a Delete invalid relations button to remove them.&lt;br /&gt;
&lt;br /&gt;
== Creating a New Datatable ==&lt;br /&gt;
# Click the New datatable button to open the &amp;quot;New datatable&amp;quot; side panel.&lt;br /&gt;
# Enter a unique name for your datatable in the Datatable name field.&lt;br /&gt;
# Click Save.&lt;br /&gt;
The new datatable will be created and will appear selected in the diagram, automatically opening the &amp;quot;Datatable details&amp;quot; panel for further configuration.&amp;lt;br&amp;gt;&lt;br /&gt;
The Save button is disabled if the chosen name is already in use by another datatable in the project.&lt;br /&gt;
&lt;br /&gt;
== Datatable Details ==&lt;br /&gt;
To edit an existing datatable, select it in the diagram to open the Datatable details panel. This panel has three tabs: Properties, Columns, and Data location.&lt;br /&gt;
&lt;br /&gt;
=== Properties Tab ===&lt;br /&gt;
This tab displays key information about the datatable. The Properties tab has the following editable Fields:&lt;br /&gt;
* &#039;&#039;&#039;Datatable name&#039;&#039;&#039;: The name of the datatable. Must be unique within the project.&lt;br /&gt;
* &#039;&#039;&#039;Description&#039;&#039;&#039;: An optional, multi-line text field for notes.&lt;br /&gt;
&lt;br /&gt;
The Properties tab has the following read-only fields:&lt;br /&gt;
* &#039;&#039;&#039;Datatable ID&#039;&#039;&#039;: The system-assigned numeric ID.&lt;br /&gt;
* &#039;&#039;&#039;Snowflake object type&#039;&#039;&#039;: Shows if the datatable is a Table or a View in Snowflake.&lt;br /&gt;
* &#039;&#039;&#039;Row count&#039;&#039;&#039;: The number of rows in the datatable.&lt;br /&gt;
* &#039;&#039;&#039;Column count&#039;&#039;&#039;: The number of columns in the datatable.&lt;br /&gt;
* &#039;&#039;&#039;Data changed&#039;&#039;&#039;: Timestamp of the last data load performed via QPR ProcessAnalyzer.&lt;br /&gt;
* &#039;&#039;&#039;Data changed by&#039;&#039;&#039;: The user who performed the last data load.&lt;br /&gt;
* &#039;&#039;&#039;Properties changed&#039;&#039;&#039;: Timestamp of the last change to the datatable&#039;s properties (e.g., name, columns).&lt;br /&gt;
* &#039;&#039;&#039;Properties changed by&#039;&#039;&#039;: The user who last changed the properties.&lt;br /&gt;
* &#039;&#039;&#039;Created&#039;&#039;&#039;: Timestamp of the datatable&#039;s creation.&lt;br /&gt;
* &#039;&#039;&#039;Created by&#039;&#039;&#039;: The user who created the datatable.&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Save&#039;&#039;&#039; to apply any changes made to the name or description.&lt;br /&gt;
&lt;br /&gt;
=== Columns Tab ===&lt;br /&gt;
This tab shows a table of all columns in the datatable, allowing you to add, edit, reorder, and delete them.&lt;br /&gt;
&lt;br /&gt;
==== Editing a Column ====&lt;br /&gt;
* To rename a column, simply edit the text in the Column name field. The change is saved automatically when you click outside the textbox. Duplicate column names are not allowed.&lt;br /&gt;
* Use the Key checkbox to designate a column as part of the datatable&#039;s primary key.&lt;br /&gt;
Note that the Data type of an existing column cannot be changed.&lt;br /&gt;
&lt;br /&gt;
==== Adding a New Column ====&lt;br /&gt;
# Click on the &amp;quot;Add column&amp;quot; row at the bottom of the table.&lt;br /&gt;
# Enter a Column name.&lt;br /&gt;
# Select the Data type from the dropdown: Text (default), Decimal, Integer, Date, or Boolean.&lt;br /&gt;
# Check the Key box if it&#039;s a primary key column.&lt;br /&gt;
# Click the save button on that row to create the column. The button is only active when a valid column name is entered.&lt;br /&gt;
&lt;br /&gt;
==== Reordering and Deleting Columns ====&lt;br /&gt;
* Drag and drop rows using the handle to reorder columns.&lt;br /&gt;
* Click the trashcan icon at the end of a row to delete a column.&lt;br /&gt;
&lt;br /&gt;
=== Data Location Tab ===&lt;br /&gt;
This tab specifies where the datatable&#039;s data is stored in Snowflake. You can link a datatable to an existing Snowflake table or let the system manage it. The following fields are available:&lt;br /&gt;
* &#039;&#039;&#039;Snowflake database&#039;&#039;&#039;: The database name. Leave empty to use the default from the connection string.&lt;br /&gt;
* &#039;&#039;&#039;Snowflake schema&#039;&#039;&#039;: The schema name. Leave empty to use the default.&lt;br /&gt;
* &#039;&#039;&#039;Snowflake table&#039;&#039;&#039;: The table or view name. Leave empty to use a system-defined table.&lt;br /&gt;
Note: Table names cannot start with &amp;quot;pa_dt&amp;quot; or &amp;quot;qprpa_dt&amp;quot; as these are reserved prefixes.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
If you specify a database, you must also specify the schema and table for the changes to be saved.&lt;br /&gt;
&lt;br /&gt;
=== Deleting a Datatable ===&lt;br /&gt;
To delete a datatable, click the &#039;&#039;&#039;Delete&#039;&#039;&#039; button. This button is hidden if you do not have the DeleteModel permission.&lt;br /&gt;
&lt;br /&gt;
== Managing Relations (Foreign Keys) ==&lt;br /&gt;
Relations define how your datatables are linked. You can create and manage these from the Data Schema diagram.&lt;br /&gt;
&lt;br /&gt;
=== Creating a New Relation ===&lt;br /&gt;
# Click the &#039;&#039;&#039;New relation&#039;&#039;&#039; button to open the &amp;quot;New relation&amp;quot; side panel.&lt;br /&gt;
# Define the relation by selecting the source and target datatables and columns:&lt;br /&gt;
#* Source datatable: The table containing the foreign key.&lt;br /&gt;
#* Target datatable: The table the foreign key points to.&lt;br /&gt;
#* Source column: The column in the source table.&lt;br /&gt;
#* Target column: The column in the target table.&lt;br /&gt;
#Click Create.&lt;br /&gt;
The new relation will appear as a line connecting the two datatables in the diagram.&lt;br /&gt;
&lt;br /&gt;
=== Editing a Relation ===&lt;br /&gt;
To edit an existing relation, select it in the diagram to open the &#039;&#039;&#039;Relation details&#039;&#039;&#039; panel.&lt;br /&gt;
&lt;br /&gt;
==== Defining Column Pairs ====&lt;br /&gt;
* A relation is defined by at least one pair of columns. Use the &#039;&#039;&#039;Source datatable&#039;&#039;&#039;, &#039;&#039;&#039;Target datatable&#039;&#039;&#039;, &#039;&#039;&#039;Source column&#039;&#039;&#039;, and &#039;&#039;&#039;Target column&#039;&#039;&#039; dropdowns to define the link.&lt;br /&gt;
* Only columns with Text or Integer data types can be used in a relation.&lt;br /&gt;
* You can add more column pairs for composite keys by clicking the &amp;quot;Add column pair&amp;quot; button.&lt;br /&gt;
* Each additional column pair can be deleted by clicking its delete button.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Searching&#039;&#039;&#039;: All dropdown lists include a search field to help you quickly find datatables or columns by name. The search is case-insensitive.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Saving Changes&#039;&#039;&#039;: Click the Save button to apply your changes. The button is disabled if any dropdown is empty or if the same column is used in multiple pairs within the same relation.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Automatic Closing&#039;&#039;&#039;: The panel will close without saving if you select another item or click on an empty space in the diagram.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Deleting a Relation ====&lt;br /&gt;
To delete a relation, click the &#039;&#039;&#039;Delete&#039;&#039;&#039; button in the &#039;&#039;&#039;Relation details&#039;&#039;&#039; panel. A confirmation dialog will appear.&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=Data_Schema_Dialog&amp;diff=28124</id>
		<title>Data Schema Dialog</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=Data_Schema_Dialog&amp;diff=28124"/>
		<updated>2026-04-16T13:27:18Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63602&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Data Schema dialog in QPR ProcessAnalyzer provides a visual way to manage your project&#039;s Snowflake datatables and the relationships (foreign keys) between them.&amp;lt;br&amp;gt;&lt;br /&gt;
The Data Schema dialog displays an entity-relationship (ER) diagram of your datatables and their relations. The ER diagram automatically arranges the datatables and relations for a clear overview. You cannot manually change the position of items.&lt;br /&gt;
&lt;br /&gt;
You can zoom in and out, and pan across the diagram to explore your data schema. The view is constrained to keep the diagram visible. Clicking on a datatable or a relation in the diagram will select it and open a corresponding details panel on the side, allowing you to view and edit its properties. Clicking on an empty area of the diagram will unselect any item and close the panel.&amp;lt;br&amp;gt;&lt;br /&gt;
If your project has no datatables to display, a message &amp;quot;Start by adding a datatable&amp;quot; will appear.&lt;br /&gt;
&lt;br /&gt;
Note that datatables stored in SQL Server or those used in an object-centric model (Objects, Events, EventToObject, ObjectToObject) are not displayed in this dialog.&lt;br /&gt;
&lt;br /&gt;
== Column Display ==&lt;br /&gt;
A dropdown menu allows you to control the level of detail shown for columns in the datatables. The following selections are available:&lt;br /&gt;
* &#039;&#039;&#039;Don&#039;t show columns&#039;&#039;&#039;: Hides all columns for a clean, high-level view.&lt;br /&gt;
* &#039;&#039;&#039;Show key and relation columns&#039;&#039;&#039;: Displays only primary keys, foreign keys, and the columns they target.&lt;br /&gt;
* &#039;&#039;&#039;Show all columns&#039;&#039;&#039;: Shows every column for all datatables in the diagram.&lt;br /&gt;
&lt;br /&gt;
== Permissions ==&lt;br /&gt;
Your ability to make changes is determined by your project permissions. If you lack GenericWrite permissions, all fields will be read-only, and buttons for creating new items will be hidden. Deleting datatables requires the DeleteModel permission.&lt;br /&gt;
&lt;br /&gt;
== Handling Invalid Relations ==&lt;br /&gt;
When the dialog opens, it checks for invalid relations (e.g., a relation pointing to a non-existent datatable or column). If any are found, an error message will appear with a Delete invalid relations button to remove them.&lt;br /&gt;
&lt;br /&gt;
== Creating a New Datatable ==&lt;br /&gt;
# Click the New datatable button to open the &amp;quot;New datatable&amp;quot; side panel.&lt;br /&gt;
# Enter a unique name for your datatable in the Datatable name field.&lt;br /&gt;
# Click Save.&lt;br /&gt;
The new datatable will be created and will appear selected in the diagram, automatically opening the &amp;quot;Datatable details&amp;quot; panel for further configuration.&amp;lt;br&amp;gt;&lt;br /&gt;
The Save button is disabled if the chosen name is already in use by another datatable in the project.&lt;br /&gt;
&lt;br /&gt;
== Datatable Details ==&lt;br /&gt;
To edit an existing datatable, select it in the diagram to open the Datatable details panel. This panel has three tabs: Properties, Columns, and Data location.&lt;br /&gt;
&lt;br /&gt;
=== Properties Tab ===&lt;br /&gt;
This tab displays key information about the datatable. The Properties tab has the following editable Fields:&lt;br /&gt;
* &#039;&#039;&#039;Datatable name&#039;&#039;&#039;: The name of the datatable. Must be unique within the project.&lt;br /&gt;
* &#039;&#039;&#039;Description&#039;&#039;&#039;: An optional, multi-line text field for notes.&lt;br /&gt;
&lt;br /&gt;
The Properties tab has the following read-only fields:&lt;br /&gt;
* &#039;&#039;&#039;Datatable ID&#039;&#039;&#039;: The system-assigned numeric ID.&lt;br /&gt;
* &#039;&#039;&#039;Snowflake object type&#039;&#039;&#039;: Shows if the datatable is a Table or a View in Snowflake.&lt;br /&gt;
* &#039;&#039;&#039;Row count&#039;&#039;&#039;: The number of rows in the datatable.&lt;br /&gt;
* &#039;&#039;&#039;Column count&#039;&#039;&#039;: The number of columns in the datatable.&lt;br /&gt;
* &#039;&#039;&#039;Data changed&#039;&#039;&#039;: Timestamp of the last data load performed via QPR ProcessAnalyzer.&lt;br /&gt;
* &#039;&#039;&#039;Data changed by&#039;&#039;&#039;: The user who performed the last data load.&lt;br /&gt;
* &#039;&#039;&#039;Properties changed&#039;&#039;&#039;: Timestamp of the last change to the datatable&#039;s properties (e.g., name, columns).&lt;br /&gt;
* &#039;&#039;&#039;Properties changed by&#039;&#039;&#039;: The user who last changed the properties.&lt;br /&gt;
* &#039;&#039;&#039;Created&#039;&#039;&#039;: Timestamp of the datatable&#039;s creation.&lt;br /&gt;
* &#039;&#039;&#039;Created by&#039;&#039;&#039;: The user who created the datatable.&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Save&#039;&#039;&#039; to apply any changes made to the name or description.&lt;br /&gt;
&lt;br /&gt;
=== Columns Tab ===&lt;br /&gt;
This tab shows a table of all columns in the datatable, allowing you to add, edit, reorder, and delete them.&lt;br /&gt;
&lt;br /&gt;
==== Editing a Column ====&lt;br /&gt;
* To rename a column, simply edit the text in the Column name field. The change is saved automatically when you click outside the textbox. Duplicate column names are not allowed.&lt;br /&gt;
* Use the Key checkbox to designate a column as part of the datatable&#039;s primary key.&lt;br /&gt;
Note that the Data type of an existing column cannot be changed.&lt;br /&gt;
&lt;br /&gt;
==== Adding a New Column ====&lt;br /&gt;
# Click on the &amp;quot;Add column&amp;quot; row at the bottom of the table.&lt;br /&gt;
# Enter a Column name.&lt;br /&gt;
# Select the Data type from the dropdown: Text (default), Decimal, Integer, Date, or Boolean.&lt;br /&gt;
# Check the Key box if it&#039;s a primary key column.&lt;br /&gt;
# Click the save button on that row to create the column. The button is only active when a valid column name is entered.&lt;br /&gt;
&lt;br /&gt;
==== Reordering and Deleting Columns ====&lt;br /&gt;
* Drag and drop rows using the handle to reorder columns.&lt;br /&gt;
* Click the trashcan icon at the end of a row to delete a column.&lt;br /&gt;
&lt;br /&gt;
=== Data Location Tab ===&lt;br /&gt;
This tab specifies where the datatable&#039;s data is stored in Snowflake. You can link a datatable to an existing Snowflake table or let the system manage it. The following fields are available:&lt;br /&gt;
* &#039;&#039;&#039;Snowflake database&#039;&#039;&#039;: The database name. Leave empty to use the default from the connection string.&lt;br /&gt;
* &#039;&#039;&#039;Snowflake schema&#039;&#039;&#039;: The schema name. Leave empty to use the default.&lt;br /&gt;
* &#039;&#039;&#039;Snowflake table&#039;&#039;&#039;: The table or view name. Leave empty to use a system-defined table.&lt;br /&gt;
Note: Table names cannot start with &amp;quot;pa_dt&amp;quot; or &amp;quot;qprpa_dt&amp;quot; as these are reserved prefixes.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
If you specify a database, you must also specify the schema and table for the changes to be saved.&lt;br /&gt;
&lt;br /&gt;
=== Deleting a Datatable ===&lt;br /&gt;
To delete a datatable, click the &#039;&#039;&#039;Delete&#039;&#039;&#039; button. This button is hidden if you do not have the DeleteModel permission.&lt;br /&gt;
&lt;br /&gt;
== Managing Relations (Foreign Keys) ==&lt;br /&gt;
Relations define how your datatables are linked. You can create and manage these from the Data Schema diagram.&lt;br /&gt;
&lt;br /&gt;
=== Creating a New Relation ===&lt;br /&gt;
# Click the &#039;&#039;&#039;New relation&#039;&#039;&#039; button to open the &amp;quot;New relation&amp;quot; side panel.&lt;br /&gt;
# Define the relation by selecting the source and target datatables and columns:&lt;br /&gt;
#* Source datatable: The table containing the foreign key.&lt;br /&gt;
#* Target datatable: The table the foreign key points to.&lt;br /&gt;
#* Source column: The column in the source table.&lt;br /&gt;
#* Target column: The column in the target table.&lt;br /&gt;
#Click Create.&lt;br /&gt;
The new relation will appear as a line connecting the two datatables in the diagram.&lt;br /&gt;
&lt;br /&gt;
=== Editing a Relation ===&lt;br /&gt;
To edit an existing relation, select it in the diagram to open the &#039;&#039;&#039;Relation details&#039;&#039;&#039; panel.&lt;br /&gt;
&lt;br /&gt;
==== Defining Column Pairs ====&lt;br /&gt;
* A relation is defined by at least one pair of columns. Use the &#039;&#039;&#039;Source datatable&#039;&#039;&#039;, &#039;&#039;&#039;Target datatable&#039;&#039;&#039;, &#039;&#039;&#039;Source column&#039;&#039;&#039;, and &#039;&#039;&#039;Target column&#039;&#039;&#039; dropdowns to define the link.&lt;br /&gt;
* Only columns with Text or Integer data types can be used in a relation.&lt;br /&gt;
* You can add more column pairs for composite keys by clicking the &amp;quot;Add column pair&amp;quot; button.&lt;br /&gt;
* Each additional column pair can be deleted by clicking its delete button.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Searching&#039;&#039;&#039;: All dropdown lists include a search field to help you quickly find datatables or columns by name. The search is case-insensitive.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Saving Changes&#039;&#039;&#039;: Click the Save button to apply your changes. The button is disabled if any dropdown is empty or if the same column is used in multiple pairs within the same relation.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Automatic Closing&#039;&#039;&#039;: The panel will close without saving if you select another item or click on an empty space in the diagram.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Deleting a Relation ====&lt;br /&gt;
To delete a relation, click the &#039;&#039;&#039;Delete&#039;&#039;&#039; button in the &#039;&#039;&#039;Relation details&#039;&#039;&#039; panel. A confirmation dialog will appear.&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=Data_Schema_Dialog&amp;diff=28123</id>
		<title>Data Schema Dialog</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=Data_Schema_Dialog&amp;diff=28123"/>
		<updated>2026-04-16T13:26:49Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63602&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Data Schema dialog in QPR ProcessAnalyzer provides a visual way to manage your project&#039;s Snowflake datatables and the relationships (foreign keys) between them.&amp;lt;br&amp;gt;&lt;br /&gt;
The Data Schema dialog displays an entity-relationship (ER) diagram of your datatables and their relations. The ER diagram automatically arranges the datatables and relations for a clear overview. You cannot manually change the position of items.&lt;br /&gt;
&lt;br /&gt;
You can zoom in and out, and pan across the diagram to explore your data schema. The view is constrained to keep the diagram visible. Clicking on a datatable or a relation in the diagram will select it and open a corresponding details panel on the side, allowing you to view and edit its properties. Clicking on an empty area of the diagram will unselect any item and close the panel.&lt;br /&gt;
If your project has no datatables to display, a message &amp;quot;Start by adding a datatable&amp;quot; will appear.&lt;br /&gt;
&lt;br /&gt;
Datatables stored in SQL Server or those used in an object-centric model (Objects, Events, EventToObject, ObjectToObject) are not displayed in this dialog.&lt;br /&gt;
&lt;br /&gt;
== Column Display ==&lt;br /&gt;
A dropdown menu allows you to control the level of detail shown for columns in the datatables. The following selections are available:&lt;br /&gt;
* &#039;&#039;&#039;Don&#039;t show columns&#039;&#039;&#039;: Hides all columns for a clean, high-level view.&lt;br /&gt;
* &#039;&#039;&#039;Show key and relation columns&#039;&#039;&#039;: Displays only primary keys, foreign keys, and the columns they target.&lt;br /&gt;
* &#039;&#039;&#039;Show all columns&#039;&#039;&#039;: Shows every column for all datatables in the diagram.&lt;br /&gt;
&lt;br /&gt;
== Permissions ==&lt;br /&gt;
Your ability to make changes is determined by your project permissions. If you lack GenericWrite permissions, all fields will be read-only, and buttons for creating new items will be hidden. Deleting datatables requires the DeleteModel permission.&lt;br /&gt;
&lt;br /&gt;
== Handling Invalid Relations ==&lt;br /&gt;
When the dialog opens, it checks for invalid relations (e.g., a relation pointing to a non-existent datatable or column). If any are found, an error message will appear with a Delete invalid relations button to remove them.&lt;br /&gt;
&lt;br /&gt;
== Creating a New Datatable ==&lt;br /&gt;
# Click the New datatable button to open the &amp;quot;New datatable&amp;quot; side panel.&lt;br /&gt;
# Enter a unique name for your datatable in the Datatable name field.&lt;br /&gt;
# Click Save.&lt;br /&gt;
The new datatable will be created and will appear selected in the diagram, automatically opening the &amp;quot;Datatable details&amp;quot; panel for further configuration.&amp;lt;br&amp;gt;&lt;br /&gt;
The Save button is disabled if the chosen name is already in use by another datatable in the project.&lt;br /&gt;
&lt;br /&gt;
== Datatable Details ==&lt;br /&gt;
To edit an existing datatable, select it in the diagram to open the Datatable details panel. This panel has three tabs: Properties, Columns, and Data location.&lt;br /&gt;
&lt;br /&gt;
=== Properties Tab ===&lt;br /&gt;
This tab displays key information about the datatable. The Properties tab has the following editable Fields:&lt;br /&gt;
* &#039;&#039;&#039;Datatable name&#039;&#039;&#039;: The name of the datatable. Must be unique within the project.&lt;br /&gt;
* &#039;&#039;&#039;Description&#039;&#039;&#039;: An optional, multi-line text field for notes.&lt;br /&gt;
&lt;br /&gt;
The Properties tab has the following read-only fields:&lt;br /&gt;
* &#039;&#039;&#039;Datatable ID&#039;&#039;&#039;: The system-assigned numeric ID.&lt;br /&gt;
* &#039;&#039;&#039;Snowflake object type&#039;&#039;&#039;: Shows if the datatable is a Table or a View in Snowflake.&lt;br /&gt;
* &#039;&#039;&#039;Row count&#039;&#039;&#039;: The number of rows in the datatable.&lt;br /&gt;
* &#039;&#039;&#039;Column count&#039;&#039;&#039;: The number of columns in the datatable.&lt;br /&gt;
* &#039;&#039;&#039;Data changed&#039;&#039;&#039;: Timestamp of the last data load performed via QPR ProcessAnalyzer.&lt;br /&gt;
* &#039;&#039;&#039;Data changed by&#039;&#039;&#039;: The user who performed the last data load.&lt;br /&gt;
* &#039;&#039;&#039;Properties changed&#039;&#039;&#039;: Timestamp of the last change to the datatable&#039;s properties (e.g., name, columns).&lt;br /&gt;
* &#039;&#039;&#039;Properties changed by&#039;&#039;&#039;: The user who last changed the properties.&lt;br /&gt;
* &#039;&#039;&#039;Created&#039;&#039;&#039;: Timestamp of the datatable&#039;s creation.&lt;br /&gt;
* &#039;&#039;&#039;Created by&#039;&#039;&#039;: The user who created the datatable.&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Save&#039;&#039;&#039; to apply any changes made to the name or description.&lt;br /&gt;
&lt;br /&gt;
=== Columns Tab ===&lt;br /&gt;
This tab shows a table of all columns in the datatable, allowing you to add, edit, reorder, and delete them.&lt;br /&gt;
&lt;br /&gt;
==== Editing a Column ====&lt;br /&gt;
* To rename a column, simply edit the text in the Column name field. The change is saved automatically when you click outside the textbox. Duplicate column names are not allowed.&lt;br /&gt;
* Use the Key checkbox to designate a column as part of the datatable&#039;s primary key.&lt;br /&gt;
Note that the Data type of an existing column cannot be changed.&lt;br /&gt;
&lt;br /&gt;
==== Adding a New Column ====&lt;br /&gt;
# Click on the &amp;quot;Add column&amp;quot; row at the bottom of the table.&lt;br /&gt;
# Enter a Column name.&lt;br /&gt;
# Select the Data type from the dropdown: Text (default), Decimal, Integer, Date, or Boolean.&lt;br /&gt;
# Check the Key box if it&#039;s a primary key column.&lt;br /&gt;
# Click the save button on that row to create the column. The button is only active when a valid column name is entered.&lt;br /&gt;
&lt;br /&gt;
==== Reordering and Deleting Columns ====&lt;br /&gt;
* Drag and drop rows using the handle to reorder columns.&lt;br /&gt;
* Click the trashcan icon at the end of a row to delete a column.&lt;br /&gt;
&lt;br /&gt;
=== Data Location Tab ===&lt;br /&gt;
This tab specifies where the datatable&#039;s data is stored in Snowflake. You can link a datatable to an existing Snowflake table or let the system manage it. The following fields are available:&lt;br /&gt;
* &#039;&#039;&#039;Snowflake database&#039;&#039;&#039;: The database name. Leave empty to use the default from the connection string.&lt;br /&gt;
* &#039;&#039;&#039;Snowflake schema&#039;&#039;&#039;: The schema name. Leave empty to use the default.&lt;br /&gt;
* &#039;&#039;&#039;Snowflake table&#039;&#039;&#039;: The table or view name. Leave empty to use a system-defined table.&lt;br /&gt;
Note: Table names cannot start with &amp;quot;pa_dt&amp;quot; or &amp;quot;qprpa_dt&amp;quot; as these are reserved prefixes.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
If you specify a database, you must also specify the schema and table for the changes to be saved.&lt;br /&gt;
&lt;br /&gt;
=== Deleting a Datatable ===&lt;br /&gt;
To delete a datatable, click the &#039;&#039;&#039;Delete&#039;&#039;&#039; button. This button is hidden if you do not have the DeleteModel permission.&lt;br /&gt;
&lt;br /&gt;
== Managing Relations (Foreign Keys) ==&lt;br /&gt;
Relations define how your datatables are linked. You can create and manage these from the Data Schema diagram.&lt;br /&gt;
&lt;br /&gt;
=== Creating a New Relation ===&lt;br /&gt;
# Click the &#039;&#039;&#039;New relation&#039;&#039;&#039; button to open the &amp;quot;New relation&amp;quot; side panel.&lt;br /&gt;
# Define the relation by selecting the source and target datatables and columns:&lt;br /&gt;
#* Source datatable: The table containing the foreign key.&lt;br /&gt;
#* Target datatable: The table the foreign key points to.&lt;br /&gt;
#* Source column: The column in the source table.&lt;br /&gt;
#* Target column: The column in the target table.&lt;br /&gt;
#Click Create.&lt;br /&gt;
The new relation will appear as a line connecting the two datatables in the diagram.&lt;br /&gt;
&lt;br /&gt;
=== Editing a Relation ===&lt;br /&gt;
To edit an existing relation, select it in the diagram to open the &#039;&#039;&#039;Relation details&#039;&#039;&#039; panel.&lt;br /&gt;
&lt;br /&gt;
==== Defining Column Pairs ====&lt;br /&gt;
* A relation is defined by at least one pair of columns. Use the &#039;&#039;&#039;Source datatable&#039;&#039;&#039;, &#039;&#039;&#039;Target datatable&#039;&#039;&#039;, &#039;&#039;&#039;Source column&#039;&#039;&#039;, and &#039;&#039;&#039;Target column&#039;&#039;&#039; dropdowns to define the link.&lt;br /&gt;
* Only columns with Text or Integer data types can be used in a relation.&lt;br /&gt;
* You can add more column pairs for composite keys by clicking the &amp;quot;Add column pair&amp;quot; button.&lt;br /&gt;
* Each additional column pair can be deleted by clicking its delete button.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Searching&#039;&#039;&#039;: All dropdown lists include a search field to help you quickly find datatables or columns by name. The search is case-insensitive.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Saving Changes&#039;&#039;&#039;: Click the Save button to apply your changes. The button is disabled if any dropdown is empty or if the same column is used in multiple pairs within the same relation.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Automatic Closing&#039;&#039;&#039;: The panel will close without saving if you select another item or click on an empty space in the diagram.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Deleting a Relation ====&lt;br /&gt;
To delete a relation, click the &#039;&#039;&#039;Delete&#039;&#039;&#039; button in the &#039;&#039;&#039;Relation details&#039;&#039;&#039; panel. A confirmation dialog will appear.&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=Data_Schema_Dialog&amp;diff=28122</id>
		<title>Data Schema Dialog</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=Data_Schema_Dialog&amp;diff=28122"/>
		<updated>2026-04-16T13:25:55Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63602&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Data Schema dialog in QPR ProcessAnalyzer provides a visual way to manage your project&#039;s Snowflake datatables and the relationships (foreign keys) between them.&amp;lt;br&amp;gt;&lt;br /&gt;
The Data Schema dialog displays an entity-relationship (ER) diagram of your datatables and their relations. The ER diagram automatically arranges the datatables and relations for a clear overview. You cannot manually change the position of items.&lt;br /&gt;
&lt;br /&gt;
You can zoom in and out, and pan across the diagram to explore your data schema. The view is constrained to keep the diagram visible.&lt;br /&gt;
&lt;br /&gt;
Interaction: Clicking on a datatable or a relation in the diagram will select it and open a corresponding details panel on the side, allowing you to view and edit its properties. Clicking on an empty area of the diagram will unselect any item and close the panel.&lt;br /&gt;
Initial State: If your project has no datatables to display, a message &amp;quot;Start by adding a datatable&amp;quot; will appear.&lt;br /&gt;
&lt;br /&gt;
Datatables stored in SQL Server or those used in an object-centric model (Objects, Events, EventToObject, ObjectToObject) are not displayed in this dialog.&lt;br /&gt;
&lt;br /&gt;
== Column Display ==&lt;br /&gt;
A dropdown menu allows you to control the level of detail shown for columns in the datatables. The following selections are available:&lt;br /&gt;
* &#039;&#039;&#039;Don&#039;t show columns&#039;&#039;&#039;: Hides all columns for a clean, high-level view.&lt;br /&gt;
* &#039;&#039;&#039;Show key and relation columns&#039;&#039;&#039;: Displays only primary keys, foreign keys, and the columns they target.&lt;br /&gt;
* &#039;&#039;&#039;Show all columns&#039;&#039;&#039;: Shows every column for all datatables in the diagram.&lt;br /&gt;
&lt;br /&gt;
== Permissions ==&lt;br /&gt;
Your ability to make changes is determined by your project permissions. If you lack GenericWrite permissions, all fields will be read-only, and buttons for creating new items will be hidden. Deleting datatables requires the DeleteModel permission.&lt;br /&gt;
&lt;br /&gt;
== Handling Invalid Relations ==&lt;br /&gt;
When the dialog opens, it checks for invalid relations (e.g., a relation pointing to a non-existent datatable or column). If any are found, an error message will appear with a Delete invalid relations button to remove them.&lt;br /&gt;
&lt;br /&gt;
== Creating a New Datatable ==&lt;br /&gt;
# Click the New datatable button to open the &amp;quot;New datatable&amp;quot; side panel.&lt;br /&gt;
# Enter a unique name for your datatable in the Datatable name field.&lt;br /&gt;
# Click Save.&lt;br /&gt;
The new datatable will be created and will appear selected in the diagram, automatically opening the &amp;quot;Datatable details&amp;quot; panel for further configuration.&amp;lt;br&amp;gt;&lt;br /&gt;
The Save button is disabled if the chosen name is already in use by another datatable in the project.&lt;br /&gt;
&lt;br /&gt;
== Datatable Details ==&lt;br /&gt;
To edit an existing datatable, select it in the diagram to open the Datatable details panel. This panel has three tabs: Properties, Columns, and Data location.&lt;br /&gt;
&lt;br /&gt;
=== Properties Tab ===&lt;br /&gt;
This tab displays key information about the datatable. The Properties tab has the following editable Fields:&lt;br /&gt;
* &#039;&#039;&#039;Datatable name&#039;&#039;&#039;: The name of the datatable. Must be unique within the project.&lt;br /&gt;
* &#039;&#039;&#039;Description&#039;&#039;&#039;: An optional, multi-line text field for notes.&lt;br /&gt;
&lt;br /&gt;
The Properties tab has the following read-only fields:&lt;br /&gt;
* &#039;&#039;&#039;Datatable ID&#039;&#039;&#039;: The system-assigned numeric ID.&lt;br /&gt;
* &#039;&#039;&#039;Snowflake object type&#039;&#039;&#039;: Shows if the datatable is a Table or a View in Snowflake.&lt;br /&gt;
* &#039;&#039;&#039;Row count&#039;&#039;&#039;: The number of rows in the datatable.&lt;br /&gt;
* &#039;&#039;&#039;Column count&#039;&#039;&#039;: The number of columns in the datatable.&lt;br /&gt;
* &#039;&#039;&#039;Data changed&#039;&#039;&#039;: Timestamp of the last data load performed via QPR ProcessAnalyzer.&lt;br /&gt;
* &#039;&#039;&#039;Data changed by&#039;&#039;&#039;: The user who performed the last data load.&lt;br /&gt;
* &#039;&#039;&#039;Properties changed&#039;&#039;&#039;: Timestamp of the last change to the datatable&#039;s properties (e.g., name, columns).&lt;br /&gt;
* &#039;&#039;&#039;Properties changed by&#039;&#039;&#039;: The user who last changed the properties.&lt;br /&gt;
* &#039;&#039;&#039;Created&#039;&#039;&#039;: Timestamp of the datatable&#039;s creation.&lt;br /&gt;
* &#039;&#039;&#039;Created by&#039;&#039;&#039;: The user who created the datatable.&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Save&#039;&#039;&#039; to apply any changes made to the name or description.&lt;br /&gt;
&lt;br /&gt;
=== Columns Tab ===&lt;br /&gt;
This tab shows a table of all columns in the datatable, allowing you to add, edit, reorder, and delete them.&lt;br /&gt;
&lt;br /&gt;
==== Editing a Column ====&lt;br /&gt;
* To rename a column, simply edit the text in the Column name field. The change is saved automatically when you click outside the textbox. Duplicate column names are not allowed.&lt;br /&gt;
* Use the Key checkbox to designate a column as part of the datatable&#039;s primary key.&lt;br /&gt;
Note that the Data type of an existing column cannot be changed.&lt;br /&gt;
&lt;br /&gt;
==== Adding a New Column ====&lt;br /&gt;
# Click on the &amp;quot;Add column&amp;quot; row at the bottom of the table.&lt;br /&gt;
# Enter a Column name.&lt;br /&gt;
# Select the Data type from the dropdown: Text (default), Decimal, Integer, Date, or Boolean.&lt;br /&gt;
# Check the Key box if it&#039;s a primary key column.&lt;br /&gt;
# Click the save button on that row to create the column. The button is only active when a valid column name is entered.&lt;br /&gt;
&lt;br /&gt;
==== Reordering and Deleting Columns ====&lt;br /&gt;
* Drag and drop rows using the handle to reorder columns.&lt;br /&gt;
* Click the trashcan icon at the end of a row to delete a column.&lt;br /&gt;
&lt;br /&gt;
=== Data Location Tab ===&lt;br /&gt;
This tab specifies where the datatable&#039;s data is stored in Snowflake. You can link a datatable to an existing Snowflake table or let the system manage it. The following fields are available:&lt;br /&gt;
* &#039;&#039;&#039;Snowflake database&#039;&#039;&#039;: The database name. Leave empty to use the default from the connection string.&lt;br /&gt;
* &#039;&#039;&#039;Snowflake schema&#039;&#039;&#039;: The schema name. Leave empty to use the default.&lt;br /&gt;
* &#039;&#039;&#039;Snowflake table&#039;&#039;&#039;: The table or view name. Leave empty to use a system-defined table.&lt;br /&gt;
Note: Table names cannot start with &amp;quot;pa_dt&amp;quot; or &amp;quot;qprpa_dt&amp;quot; as these are reserved prefixes.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
If you specify a database, you must also specify the schema and table for the changes to be saved.&lt;br /&gt;
&lt;br /&gt;
=== Deleting a Datatable ===&lt;br /&gt;
To delete a datatable, click the &#039;&#039;&#039;Delete&#039;&#039;&#039; button. This button is hidden if you do not have the DeleteModel permission.&lt;br /&gt;
&lt;br /&gt;
== Managing Relations (Foreign Keys) ==&lt;br /&gt;
Relations define how your datatables are linked. You can create and manage these from the Data Schema diagram.&lt;br /&gt;
&lt;br /&gt;
=== Creating a New Relation ===&lt;br /&gt;
# Click the &#039;&#039;&#039;New relation&#039;&#039;&#039; button to open the &amp;quot;New relation&amp;quot; side panel.&lt;br /&gt;
# Define the relation by selecting the source and target datatables and columns:&lt;br /&gt;
#* Source datatable: The table containing the foreign key.&lt;br /&gt;
#* Target datatable: The table the foreign key points to.&lt;br /&gt;
#* Source column: The column in the source table.&lt;br /&gt;
#* Target column: The column in the target table.&lt;br /&gt;
#Click Create.&lt;br /&gt;
The new relation will appear as a line connecting the two datatables in the diagram.&lt;br /&gt;
&lt;br /&gt;
=== Editing a Relation ===&lt;br /&gt;
To edit an existing relation, select it in the diagram to open the &#039;&#039;&#039;Relation details&#039;&#039;&#039; panel.&lt;br /&gt;
&lt;br /&gt;
==== Defining Column Pairs ====&lt;br /&gt;
* A relation is defined by at least one pair of columns. Use the &#039;&#039;&#039;Source datatable&#039;&#039;&#039;, &#039;&#039;&#039;Target datatable&#039;&#039;&#039;, &#039;&#039;&#039;Source column&#039;&#039;&#039;, and &#039;&#039;&#039;Target column&#039;&#039;&#039; dropdowns to define the link.&lt;br /&gt;
* Only columns with Text or Integer data types can be used in a relation.&lt;br /&gt;
* You can add more column pairs for composite keys by clicking the &amp;quot;Add column pair&amp;quot; button.&lt;br /&gt;
* Each additional column pair can be deleted by clicking its delete button.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Searching&#039;&#039;&#039;: All dropdown lists include a search field to help you quickly find datatables or columns by name. The search is case-insensitive.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Saving Changes&#039;&#039;&#039;: Click the Save button to apply your changes. The button is disabled if any dropdown is empty or if the same column is used in multiple pairs within the same relation.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Automatic Closing&#039;&#039;&#039;: The panel will close without saving if you select another item or click on an empty space in the diagram.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Deleting a Relation ====&lt;br /&gt;
To delete a relation, click the &#039;&#039;&#039;Delete&#039;&#039;&#039; button in the &#039;&#039;&#039;Relation details&#039;&#039;&#039; panel. A confirmation dialog will appear.&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=Data_Schema_Dialog&amp;diff=28121</id>
		<title>Data Schema Dialog</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=Data_Schema_Dialog&amp;diff=28121"/>
		<updated>2026-04-16T13:24:58Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63602&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Data Schema dialog in QPR ProcessAnalyzer provides a visual way to manage your project&#039;s Snowflake datatables and the relationships (foreign keys) between them.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Datatables stored in SQL Server or those used in an object-centric model (Objects, Events, EventToObject, ObjectToObject) are not displayed in this dialog.&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
The Data Schema dialog displays an entity-relationship (ER) diagram of your datatables and their relations. The ER diagram automatically arranges the datatables and relations for a clear overview. You cannot manually change the position of items.&lt;br /&gt;
&lt;br /&gt;
You can zoom in and out, and pan across the diagram to explore your data schema. The view is constrained to keep the diagram visible.&lt;br /&gt;
&lt;br /&gt;
Interaction: Clicking on a datatable or a relation in the diagram will select it and open a corresponding details panel on the side, allowing you to view and edit its properties. Clicking on an empty area of the diagram will unselect any item and close the panel.&lt;br /&gt;
Initial State: If your project has no datatables to display, a message &amp;quot;Start by adding a datatable&amp;quot; will appear.&lt;br /&gt;
&lt;br /&gt;
== Column Display ==&lt;br /&gt;
A dropdown menu allows you to control the level of detail shown for columns in the datatables. The following selections are available:&lt;br /&gt;
* &#039;&#039;&#039;Don&#039;t show columns&#039;&#039;&#039;: Hides all columns for a clean, high-level view.&lt;br /&gt;
* &#039;&#039;&#039;Show key and relation columns&#039;&#039;&#039;: Displays only primary keys, foreign keys, and the columns they target.&lt;br /&gt;
* &#039;&#039;&#039;Show all columns&#039;&#039;&#039;: Shows every column for all datatables in the diagram.&lt;br /&gt;
&lt;br /&gt;
== Permissions ==&lt;br /&gt;
Your ability to make changes is determined by your project permissions. If you lack GenericWrite permissions, all fields will be read-only, and buttons for creating new items will be hidden. Deleting datatables requires the DeleteModel permission.&lt;br /&gt;
&lt;br /&gt;
== Handling Invalid Relations ==&lt;br /&gt;
When the dialog opens, it checks for invalid relations (e.g., a relation pointing to a non-existent datatable or column). If any are found, an error message will appear with a Delete invalid relations button to remove them.&lt;br /&gt;
&lt;br /&gt;
== Creating a New Datatable ==&lt;br /&gt;
# Click the New datatable button to open the &amp;quot;New datatable&amp;quot; side panel.&lt;br /&gt;
# Enter a unique name for your datatable in the Datatable name field.&lt;br /&gt;
# Click Save.&lt;br /&gt;
The new datatable will be created and will appear selected in the diagram, automatically opening the &amp;quot;Datatable details&amp;quot; panel for further configuration.&amp;lt;br&amp;gt;&lt;br /&gt;
The Save button is disabled if the chosen name is already in use by another datatable in the project.&lt;br /&gt;
&lt;br /&gt;
== Datatable Details ==&lt;br /&gt;
To edit an existing datatable, select it in the diagram to open the Datatable details panel. This panel has three tabs: Properties, Columns, and Data location.&lt;br /&gt;
&lt;br /&gt;
=== Properties Tab ===&lt;br /&gt;
This tab displays key information about the datatable. The Properties tab has the following editable Fields:&lt;br /&gt;
* &#039;&#039;&#039;Datatable name&#039;&#039;&#039;: The name of the datatable. Must be unique within the project.&lt;br /&gt;
* &#039;&#039;&#039;Description&#039;&#039;&#039;: An optional, multi-line text field for notes.&lt;br /&gt;
&lt;br /&gt;
The Properties tab has the following read-only fields:&lt;br /&gt;
* &#039;&#039;&#039;Datatable ID&#039;&#039;&#039;: The system-assigned numeric ID.&lt;br /&gt;
* &#039;&#039;&#039;Snowflake object type&#039;&#039;&#039;: Shows if the datatable is a Table or a View in Snowflake.&lt;br /&gt;
* &#039;&#039;&#039;Row count&#039;&#039;&#039;: The number of rows in the datatable.&lt;br /&gt;
* &#039;&#039;&#039;Column count&#039;&#039;&#039;: The number of columns in the datatable.&lt;br /&gt;
* &#039;&#039;&#039;Data changed&#039;&#039;&#039;: Timestamp of the last data load performed via QPR ProcessAnalyzer.&lt;br /&gt;
* &#039;&#039;&#039;Data changed by&#039;&#039;&#039;: The user who performed the last data load.&lt;br /&gt;
* &#039;&#039;&#039;Properties changed&#039;&#039;&#039;: Timestamp of the last change to the datatable&#039;s properties (e.g., name, columns).&lt;br /&gt;
* &#039;&#039;&#039;Properties changed by&#039;&#039;&#039;: The user who last changed the properties.&lt;br /&gt;
* &#039;&#039;&#039;Created&#039;&#039;&#039;: Timestamp of the datatable&#039;s creation.&lt;br /&gt;
* &#039;&#039;&#039;Created by&#039;&#039;&#039;: The user who created the datatable.&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Save&#039;&#039;&#039; to apply any changes made to the name or description.&lt;br /&gt;
&lt;br /&gt;
=== Columns Tab ===&lt;br /&gt;
This tab shows a table of all columns in the datatable, allowing you to add, edit, reorder, and delete them.&lt;br /&gt;
&lt;br /&gt;
==== Editing a Column ====&lt;br /&gt;
* To rename a column, simply edit the text in the Column name field. The change is saved automatically when you click outside the textbox. Duplicate column names are not allowed.&lt;br /&gt;
* Use the Key checkbox to designate a column as part of the datatable&#039;s primary key.&lt;br /&gt;
Note that the Data type of an existing column cannot be changed.&lt;br /&gt;
&lt;br /&gt;
==== Adding a New Column ====&lt;br /&gt;
# Click on the &amp;quot;Add column&amp;quot; row at the bottom of the table.&lt;br /&gt;
# Enter a Column name.&lt;br /&gt;
# Select the Data type from the dropdown: Text (default), Decimal, Integer, Date, or Boolean.&lt;br /&gt;
# Check the Key box if it&#039;s a primary key column.&lt;br /&gt;
# Click the save button on that row to create the column. The button is only active when a valid column name is entered.&lt;br /&gt;
&lt;br /&gt;
==== Reordering and Deleting Columns ====&lt;br /&gt;
* Drag and drop rows using the handle to reorder columns.&lt;br /&gt;
* Click the trashcan icon at the end of a row to delete a column.&lt;br /&gt;
&lt;br /&gt;
=== Data Location Tab ===&lt;br /&gt;
This tab specifies where the datatable&#039;s data is stored in Snowflake. You can link a datatable to an existing Snowflake table or let the system manage it. The following fields are available:&lt;br /&gt;
* &#039;&#039;&#039;Snowflake database&#039;&#039;&#039;: The database name. Leave empty to use the default from the connection string.&lt;br /&gt;
* &#039;&#039;&#039;Snowflake schema&#039;&#039;&#039;: The schema name. Leave empty to use the default.&lt;br /&gt;
* &#039;&#039;&#039;Snowflake table&#039;&#039;&#039;: The table or view name. Leave empty to use a system-defined table.&lt;br /&gt;
Note: Table names cannot start with &amp;quot;pa_dt&amp;quot; or &amp;quot;qprpa_dt&amp;quot; as these are reserved prefixes.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
If you specify a database, you must also specify the schema and table for the changes to be saved.&lt;br /&gt;
&lt;br /&gt;
=== Deleting a Datatable ===&lt;br /&gt;
To delete a datatable, click the &#039;&#039;&#039;Delete&#039;&#039;&#039; button. This button is hidden if you do not have the DeleteModel permission.&lt;br /&gt;
&lt;br /&gt;
== Managing Relations (Foreign Keys) ==&lt;br /&gt;
Relations define how your datatables are linked. You can create and manage these from the Data Schema diagram.&lt;br /&gt;
&lt;br /&gt;
=== Creating a New Relation ===&lt;br /&gt;
# Click the &#039;&#039;&#039;New relation&#039;&#039;&#039; button to open the &amp;quot;New relation&amp;quot; side panel.&lt;br /&gt;
# Define the relation by selecting the source and target datatables and columns:&lt;br /&gt;
#* Source datatable: The table containing the foreign key.&lt;br /&gt;
#* Target datatable: The table the foreign key points to.&lt;br /&gt;
#* Source column: The column in the source table.&lt;br /&gt;
#* Target column: The column in the target table.&lt;br /&gt;
#Click Create.&lt;br /&gt;
The new relation will appear as a line connecting the two datatables in the diagram.&lt;br /&gt;
&lt;br /&gt;
=== Editing a Relation ===&lt;br /&gt;
To edit an existing relation, select it in the diagram to open the &#039;&#039;&#039;Relation details&#039;&#039;&#039; panel.&lt;br /&gt;
&lt;br /&gt;
==== Defining Column Pairs ====&lt;br /&gt;
* A relation is defined by at least one pair of columns. Use the &#039;&#039;&#039;Source datatable&#039;&#039;&#039;, &#039;&#039;&#039;Target datatable&#039;&#039;&#039;, &#039;&#039;&#039;Source column&#039;&#039;&#039;, and &#039;&#039;&#039;Target column&#039;&#039;&#039; dropdowns to define the link.&lt;br /&gt;
* Only columns with Text or Integer data types can be used in a relation.&lt;br /&gt;
* You can add more column pairs for composite keys by clicking the &amp;quot;Add column pair&amp;quot; button.&lt;br /&gt;
* Each additional column pair can be deleted by clicking its delete button.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Searching&#039;&#039;&#039;: All dropdown lists include a search field to help you quickly find datatables or columns by name. The search is case-insensitive.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Saving Changes&#039;&#039;&#039;: Click the Save button to apply your changes. The button is disabled if any dropdown is empty or if the same column is used in multiple pairs within the same relation.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Automatic Closing&#039;&#039;&#039;: The panel will close without saving if you select another item or click on an empty space in the diagram.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Deleting a Relation ====&lt;br /&gt;
To delete a relation, click the &#039;&#039;&#039;Delete&#039;&#039;&#039; button in the &#039;&#039;&#039;Relation details&#039;&#039;&#039; panel. A confirmation dialog will appear.&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=Data_Schema_Dialog&amp;diff=28120</id>
		<title>Data Schema Dialog</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=Data_Schema_Dialog&amp;diff=28120"/>
		<updated>2026-04-16T13:24:18Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63602&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Data Schema dialog in QPR ProcessAnalyzer provides a visual way to manage your project&#039;s Snowflake datatables and the relationships (foreign keys) between them.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: Datatables stored in SQL Server or those used in an object-centric model (Objects, Events, EventToObject, ObjectToObject) are not displayed in this dialog.&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
The Data Schema dialog displays an entity-relationship (ER) diagram of your datatables and their relations. The ER diagram automatically arranges the datatables and relations for a clear overview. You cannot manually change the position of items.&lt;br /&gt;
&lt;br /&gt;
You can zoom in and out, and pan across the diagram to explore your data schema. The view is constrained to keep the diagram visible.&lt;br /&gt;
&lt;br /&gt;
Interaction: Clicking on a datatable or a relation in the diagram will select it and open a corresponding details panel on the side, allowing you to view and edit its properties. Clicking on an empty area of the diagram will unselect any item and close the panel.&lt;br /&gt;
Initial State: If your project has no datatables to display, a message &amp;quot;Start by adding a datatable&amp;quot; will appear.&lt;br /&gt;
&lt;br /&gt;
== Column Display ==&lt;br /&gt;
A dropdown menu allows you to control the level of detail shown for columns in the datatables. The following selections are available:&lt;br /&gt;
* &#039;&#039;&#039;Don&#039;t show columns&#039;&#039;&#039;: Hides all columns for a clean, high-level view.&lt;br /&gt;
* &#039;&#039;&#039;Show key and relation columns&#039;&#039;&#039;: Displays only primary keys, foreign keys, and the columns they target.&lt;br /&gt;
* &#039;&#039;&#039;Show all columns&#039;&#039;&#039;: Shows every column for all datatables in the diagram.&lt;br /&gt;
&lt;br /&gt;
== Permissions ==&lt;br /&gt;
Your ability to make changes is determined by your project permissions. If you lack GenericWrite permissions, all fields will be read-only, and buttons for creating new items will be hidden. Deleting datatables requires the DeleteModel permission.&lt;br /&gt;
&lt;br /&gt;
== Handling Invalid Relations ==&lt;br /&gt;
When the dialog opens, it checks for invalid relations (e.g., a relation pointing to a non-existent datatable or column). If any are found, an error message will appear with a Delete invalid relations button to remove them.&lt;br /&gt;
&lt;br /&gt;
== Creating a New Datatable ==&lt;br /&gt;
# Click the New datatable button to open the &amp;quot;New datatable&amp;quot; side panel.&lt;br /&gt;
# Enter a unique name for your datatable in the Datatable name field.&lt;br /&gt;
# Click Save.&lt;br /&gt;
The new datatable will be created and will appear selected in the diagram, automatically opening the &amp;quot;Datatable details&amp;quot; panel for further configuration.&amp;lt;br&amp;gt;&lt;br /&gt;
The Save button is disabled if the chosen name is already in use by another datatable in the project.&lt;br /&gt;
&lt;br /&gt;
== Datatable Details ==&lt;br /&gt;
To edit an existing datatable, select it in the diagram to open the Datatable details panel. This panel has three tabs: Properties, Columns, and Data location.&lt;br /&gt;
&lt;br /&gt;
=== Properties Tab ===&lt;br /&gt;
This tab displays key information about the datatable. The Properties tab has the following editable Fields:&lt;br /&gt;
* &#039;&#039;&#039;Datatable name&#039;&#039;&#039;: The name of the datatable. Must be unique within the project.&lt;br /&gt;
* &#039;&#039;&#039;Description&#039;&#039;&#039;: An optional, multi-line text field for notes.&lt;br /&gt;
&lt;br /&gt;
The Properties tab has the following read-only fields:&lt;br /&gt;
* &#039;&#039;&#039;Datatable ID&#039;&#039;&#039;: The system-assigned numeric ID.&lt;br /&gt;
* &#039;&#039;&#039;Snowflake object type&#039;&#039;&#039;: Shows if the datatable is a Table or a View in Snowflake.&lt;br /&gt;
* &#039;&#039;&#039;Row count&#039;&#039;&#039;: The number of rows in the datatable.&lt;br /&gt;
* &#039;&#039;&#039;Column count&#039;&#039;&#039;: The number of columns in the datatable.&lt;br /&gt;
* &#039;&#039;&#039;Data changed&#039;&#039;&#039;: Timestamp of the last data load performed via QPR ProcessAnalyzer.&lt;br /&gt;
* &#039;&#039;&#039;Data changed by&#039;&#039;&#039;: The user who performed the last data load.&lt;br /&gt;
* &#039;&#039;&#039;Properties changed&#039;&#039;&#039;: Timestamp of the last change to the datatable&#039;s properties (e.g., name, columns).&lt;br /&gt;
* &#039;&#039;&#039;Properties changed by&#039;&#039;&#039;: The user who last changed the properties.&lt;br /&gt;
* &#039;&#039;&#039;Created&#039;&#039;&#039;: Timestamp of the datatable&#039;s creation.&lt;br /&gt;
* &#039;&#039;&#039;Created by&#039;&#039;&#039;: The user who created the datatable.&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Save&#039;&#039;&#039; to apply any changes made to the name or description.&lt;br /&gt;
&lt;br /&gt;
=== Columns Tab ===&lt;br /&gt;
This tab shows a table of all columns in the datatable, allowing you to add, edit, reorder, and delete them.&lt;br /&gt;
&lt;br /&gt;
==== Editing a Column ====&lt;br /&gt;
* To rename a column, simply edit the text in the Column name field. The change is saved automatically when you click outside the textbox. Duplicate column names are not allowed.&lt;br /&gt;
* Use the Key checkbox to designate a column as part of the datatable&#039;s primary key.&lt;br /&gt;
Note that the Data type of an existing column cannot be changed.&lt;br /&gt;
&lt;br /&gt;
==== Adding a New Column ====&lt;br /&gt;
# Click on the &amp;quot;Add column&amp;quot; row at the bottom of the table.&lt;br /&gt;
# Enter a Column name.&lt;br /&gt;
# Select the Data type from the dropdown: Text (default), Decimal, Integer, Date, or Boolean.&lt;br /&gt;
# Check the Key box if it&#039;s a primary key column.&lt;br /&gt;
# Click the save button on that row to create the column. The button is only active when a valid column name is entered.&lt;br /&gt;
&lt;br /&gt;
==== Reordering and Deleting Columns ====&lt;br /&gt;
* Drag and drop rows using the handle to reorder columns.&lt;br /&gt;
* Click the trashcan icon at the end of a row to delete a column.&lt;br /&gt;
&lt;br /&gt;
=== Data Location Tab ===&lt;br /&gt;
This tab specifies where the datatable&#039;s data is stored in Snowflake. You can link a datatable to an existing Snowflake table or let the system manage it. The following fields are available:&lt;br /&gt;
* &#039;&#039;&#039;Snowflake database&#039;&#039;&#039;: The database name. Leave empty to use the default from the connection string.&lt;br /&gt;
* &#039;&#039;&#039;Snowflake schema&#039;&#039;&#039;: The schema name. Leave empty to use the default.&lt;br /&gt;
* &#039;&#039;&#039;Snowflake table&#039;&#039;&#039;: The table or view name. Leave empty to use a system-defined table.&lt;br /&gt;
Note: Table names cannot start with &amp;quot;pa_dt&amp;quot; or &amp;quot;qprpa_dt&amp;quot; as these are reserved prefixes.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
If you specify a database, you must also specify the schema and table for the changes to be saved.&lt;br /&gt;
&lt;br /&gt;
=== Deleting a Datatable ===&lt;br /&gt;
To delete a datatable, click the &#039;&#039;&#039;Delete&#039;&#039;&#039; button. This button is hidden if you do not have the DeleteModel permission.&lt;br /&gt;
&lt;br /&gt;
== Managing Relations (Foreign Keys) ==&lt;br /&gt;
Relations define how your datatables are linked. You can create and manage these from the Data Schema diagram.&lt;br /&gt;
&lt;br /&gt;
=== Creating a New Relation ===&lt;br /&gt;
# Click the &#039;&#039;&#039;New relation&#039;&#039;&#039; button to open the &amp;quot;New relation&amp;quot; side panel.&lt;br /&gt;
# Define the relation by selecting the source and target datatables and columns:&lt;br /&gt;
#* Source datatable: The table containing the foreign key.&lt;br /&gt;
#* Target datatable: The table the foreign key points to.&lt;br /&gt;
#* Source column: The column in the source table.&lt;br /&gt;
#* Target column: The column in the target table.&lt;br /&gt;
#Click Create.&lt;br /&gt;
The new relation will appear as a line connecting the two datatables in the diagram.&lt;br /&gt;
&lt;br /&gt;
=== Editing a Relation ===&lt;br /&gt;
To edit an existing relation, select it in the diagram to open the &#039;&#039;&#039;Relation details&#039;&#039;&#039; panel.&lt;br /&gt;
&lt;br /&gt;
==== Defining Column Pairs ====&lt;br /&gt;
* A relation is defined by at least one pair of columns. Use the &#039;&#039;&#039;Source datatable&#039;&#039;&#039;, &#039;&#039;&#039;Target datatable&#039;&#039;&#039;, &#039;&#039;&#039;Source column&#039;&#039;&#039;, and &#039;&#039;&#039;Target column&#039;&#039;&#039; dropdowns to define the link.&lt;br /&gt;
* Only columns with Text or Integer data types can be used in a relation.&lt;br /&gt;
* You can add more column pairs for composite keys by clicking the &amp;quot;Add column pair&amp;quot; button.&lt;br /&gt;
* Each additional column pair can be deleted by clicking its delete button.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Searching&#039;&#039;&#039;: All dropdown lists include a search field to help you quickly find datatables or columns by name. The search is case-insensitive.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Saving Changes&#039;&#039;&#039;: Click the Save button to apply your changes. The button is disabled if any dropdown is empty or if the same column is used in multiple pairs within the same relation.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Automatic Closing&#039;&#039;&#039;: The panel will close without saving if you select another item or click on an empty space in the diagram.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Deleting a Relation ====&lt;br /&gt;
To delete a relation, click the &#039;&#039;&#039;Delete&#039;&#039;&#039; button in the &#039;&#039;&#039;Relation details&#039;&#039;&#039; panel. A confirmation dialog will appear.&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_Project_Workspace&amp;diff=28119</id>
		<title>QPR ProcessAnalyzer Project Workspace</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_Project_Workspace&amp;diff=28119"/>
		<updated>2026-04-16T12:36:31Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63602&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In QPR ProcessAnalyzer, &#039;&#039;dashboards&#039;&#039;, &#039;&#039;models&#039;&#039;, &#039;&#039;datatables&#039;&#039; and &#039;&#039;scripts&#039;&#039; are organized into projects. &#039;&#039;&#039;Project Workspace&#039;&#039;&#039; shows all projects in a hierarchy (on the left side) and contents of the selected project (on the right side) divided into tabs based on the type of the entity. There are tabs for dashboards, models, datatables, scripts and projects. Dashboards and datatables are described in this article and scripts are described in [[Managing Scripts]].&lt;br /&gt;
&lt;br /&gt;
The Project Workspace is opened after logging in to QPR ProcessAnalyzer. All actions, such as open, create, modify and delete, are available as buttons in the toolbar and also in the context menu, which can be opened by right clicking the target project, dashboard, datatable, model, or script.&lt;br /&gt;
&lt;br /&gt;
The projects hierarchy can be hidden by clicking the blue &#039;&#039;Collapse&#039;&#039; button in the top of the divider, to make more space for the contents table. If the Collapse button is not visible, hover the upper side of the divider with the mouse to make the button visible. To show the projects hierarchy again, click the grey &#039;&#039;Expand&#039;&#039; button on the top left of the screen.&lt;br /&gt;
&lt;br /&gt;
Access control is not taking the projects hierarchy into account. If user has permissions to a project but not its parent project, the project is accessible and shown in the top level of the projects hierarchy. Moving the project is not allowed though because it requires access to the parent project.&lt;br /&gt;
&lt;br /&gt;
There are the following requirements for names given to objects: it cannot be empty, maximum length is 440 characters, and it cannot contain the slash (/) character.&lt;br /&gt;
&lt;br /&gt;
== Projects ==&lt;br /&gt;
&lt;br /&gt;
Projects are organized into a hierarchy, where projects can contain child projects. The hierarchy is visible in the left side of the workspace, where a project can be selected to see its contents on the right side. In addition, there is the &#039;&#039;&#039;Projects&#039;&#039;&#039; tab showing child projects of the selected project. The Projects tab has two different layouts selectable: Card layout and Table layout.&lt;br /&gt;
&lt;br /&gt;
[[File:Workspace.png]]&lt;br /&gt;
&lt;br /&gt;
=== Opening Project ===&lt;br /&gt;
Project can be opened in the workspace to see its contents, by clicking the project in the left side hierarchy. Alternatively the &#039;&#039;&#039;Projects&#039;&#039;&#039; tab can be used browse projects by drilling down into child projects by clicking a project in the card view or by double-clicking a project in the table view.&lt;br /&gt;
&lt;br /&gt;
=== Changing Project Properties ===&lt;br /&gt;
Project properties can be viewed and edited in the [[Project_Properties_Dialog|Project properties dialog]] that can be opened by right-clicking the project either in the left side project hierarchy or in the table view and then selecting &#039;&#039;&#039;Properties&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Creating Project ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where you want to create a new project.&lt;br /&gt;
# Click the &#039;&#039;&#039;New&#039;&#039;&#039; button and click &#039;&#039;&#039;Project&#039;&#039;&#039;.&lt;br /&gt;
# Define a name for the projects and click &#039;&#039;&#039;Create&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Deleting Project ===&lt;br /&gt;
# Select project(s) you want to delete on the table layout in the &#039;&#039;&#039;Projects&#039;&#039;&#039; tab.&lt;br /&gt;
# Click the &#039;&#039;&#039;Delete&#039;&#039;&#039; button or right-click and select &#039;&#039;&#039;Delete&#039;&#039;&#039; from the popup menu, then click &#039;&#039;&#039;Delete&#039;&#039;&#039; for the confirmation message. (The deleted project goes to the bin.)&lt;br /&gt;
&lt;br /&gt;
A project can also be deleted by right-clicking a single project on the left side hierarchy and selecting &#039;&#039;&#039;Delete&#039;&#039;&#039; from the popup menu.&lt;br /&gt;
&lt;br /&gt;
Note that project cannot be deleted if the project or its child projects contain the currently selected model.&lt;br /&gt;
&lt;br /&gt;
=== Renaming Project ===&lt;br /&gt;
# Select the project to be renamed on the table layout in the &#039;&#039;&#039;Projects&#039;&#039;&#039; tab.&lt;br /&gt;
# Click the &#039;&#039;&#039;Rename&#039;&#039;&#039; button.&lt;br /&gt;
# Change the project name in the opening dialog and click &#039;&#039;&#039;OK&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A project can also be renamed by right-clicking a single project on the left side hierarchy and selecting &#039;&#039;&#039;Rename&#039;&#039;&#039; from the popup menu.&lt;br /&gt;
&lt;br /&gt;
=== Moving Project ===&lt;br /&gt;
Projects can be moved by dragging them with a mouse from the table layout in &#039;&#039;&#039;Projects&#039;&#039;&#039; tab to a new parent project in the left side hierarchy.&lt;br /&gt;
&lt;br /&gt;
Projects can also be moved by right-clicking the project in the left side hierarchy or on the table layout in the &#039;&#039;&#039;Projects&#039;&#039;&#039; tab, selecting the &#039;&#039;&#039;Move&#039;&#039;&#039; option in the popup menu, and then selecting the new parent project in the opening list of projects.&lt;br /&gt;
&lt;br /&gt;
=== Exporting Project ===&lt;br /&gt;
Projects can be exported to a file as follows:&lt;br /&gt;
# On the left side projects hierarchy, right-click the project you want to export. (Alternatively, the project can be selected in the &#039;&#039;&#039;Projects&#039;&#039;&#039; tab.)&lt;br /&gt;
# In the opening context menu, click &#039;&#039;&#039;Export&#039;&#039;&#039;.&lt;br /&gt;
# The project is exported to a file.&lt;br /&gt;
&lt;br /&gt;
Notes about the project export files:&lt;br /&gt;
* Export files don&#039;t contain object ID&#039;s, and new ID&#039;s are created in the import. If there are scripts that refer to objects by their ID&#039;s, the imported scripts won&#039;t work. It&#039;s a good practice to write scripts to refer to other objects by their names rather than ID&#039;s.&lt;br /&gt;
* In the export file, the &#039;&#039;ModelId&#039;&#039; dashboard variable is replaced with the &#039;&#039;ModelName&#039;&#039; variable containing the model name. In the import, the &#039;&#039;ModelName&#039;&#039; variable is replaced by the &#039;&#039;ModelId&#039;&#039; variable referring to a corresponding model created in the import. This is required because model ID&#039;s are not part of the export file, and the model name is used to refer to the model. This replacement is not supported by the chart-specific model selection, so the setting needs to be set manually after the import.&lt;br /&gt;
* Child projects are not part of the export file.&lt;br /&gt;
* Project permissions are not part of the export file.&lt;br /&gt;
* Project secrets are not part of the export file.&lt;br /&gt;
* Private filters are not part of the export file.&lt;br /&gt;
* Datatables data is not part of the export file. If you also want to export data, use the CSV export. If the data is in Snowflake and there is great amount of data, it&#039;s recommended to use Snowflake tools for exporting and importing data.&lt;br /&gt;
&lt;br /&gt;
=== Importing Project ===&lt;br /&gt;
# From the left side projects hierarchy, select the project where you want to import the project as a child project, or select the top level of the hierarchy if you want to import a top level project.&lt;br /&gt;
# Click the &#039;&#039;&#039;New&#039;&#039;&#039; button, and select &#039;&#039;&#039;Import Project&#039;&#039;&#039;.&lt;br /&gt;
# Select a &#039;&#039;&#039;.json file&#039;&#039;&#039; to be imported.&lt;br /&gt;
# Project is imported and it appears as a child project of the selected project.&lt;br /&gt;
&lt;br /&gt;
If there is already a project with the same name under the same parent project, the created project will get a slightly different name than specified in the file.&lt;br /&gt;
&lt;br /&gt;
=== Project-level Snowflake Database, Schema and Connection String===&lt;br /&gt;
In the [[Project_Properties_Dialog#Secrets|Project Properties Dialog]], the project can be linked to a Snowflake database and schema where data for the project&#039;s datatables are located. The datatables can use either the default names or user-defined custom names. &lt;br /&gt;
&lt;br /&gt;
[[Snowflake_Connection_Configuration#Set_Snowflake_ODBC_connection|Snowflake connection string]] can be set for each project separately, and then datatables in the project will use the project-level connection string instead of the global [[PA_Configuration_database_table#SnowflakeConnectionString|Snowflake connection string]]. If you need to set other Snowflake parameters than the database, schema or warehouse (such as Snowflake account or warehouse), the project-level connection string needs to be used.&lt;br /&gt;
&lt;br /&gt;
It&#039;s also possible to use both the project-level connection string and the database/schema settings.&lt;br /&gt;
&lt;br /&gt;
Note that in the Snowflake Native App, it&#039;s not possible to define different account or user in the connection string (only the warehouse can be changed).&lt;br /&gt;
&lt;br /&gt;
== Dashboards ==&lt;br /&gt;
Dashboards can be created, opened, moved, deleted, imported and exported in the &#039;&#039;&#039;Dashboards&#039;&#039;&#039; tab, which shows all dashboards in the selected project.&lt;br /&gt;
&lt;br /&gt;
=== Opening Dashboard ===&lt;br /&gt;
# Select the project where the dashboard to be opened is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Dashboards&#039;&#039;&#039; tab.&lt;br /&gt;
# Double-click the dashboard in the list, or select the dashboard with a single click and click the &#039;&#039;&#039;Open&#039;&#039;&#039; button.&lt;br /&gt;
&lt;br /&gt;
=== Creating Dashboard ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where you want to create the dashboard.&lt;br /&gt;
# Open the &#039;&#039;&#039;Dashboards&#039;&#039;&#039; tab.&lt;br /&gt;
# Click the &#039;&#039;&#039;New&#039;&#039;&#039; button and click &#039;&#039;&#039;Dashboard&#039;&#039;&#039;. The [[QPR_ProcessAnalyzer_Dashboard_Designer|dashboard designer]] opens.&lt;br /&gt;
# The dashboard can be named by opening the menu on the right and clicking &#039;&#039;&#039;Dashboard properties&#039;&#039;&#039;. The name can be defined in the &#039;&#039;&#039;General&#039;&#039;&#039; tab. The dialog can be closed by clicking the &#039;&#039;&#039;Done&#039;&#039;&#039; button.&lt;br /&gt;
# The dashboard is saved when clicking the &#039;&#039;&#039;Save&#039;&#039;&#039; button.&lt;br /&gt;
&lt;br /&gt;
Note that each dashboard in the same project needs to have a unique name.&lt;br /&gt;
&lt;br /&gt;
=== Deleting Dashboard ===&lt;br /&gt;
# Select the project where the dashboard(s) to be deleted are located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Dashboards&#039;&#039;&#039; tab.&lt;br /&gt;
# Select one or several dashboards to be deleted.&lt;br /&gt;
# Click the &#039;&#039;&#039;Delete&#039;&#039;&#039; button and click &#039;&#039;&#039;Delete&#039;&#039;&#039; to the confirmation message.&lt;br /&gt;
&lt;br /&gt;
=== Renaming Dashboard ===&lt;br /&gt;
# Select the project where the dashboard to be renamed is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Dashboards&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the dashboard to be renamed.&lt;br /&gt;
# Click the &#039;&#039;&#039;Rename&#039;&#039;&#039; button.&lt;br /&gt;
# Change the dashboard name in the opening dialog and click &#039;&#039;&#039;OK&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Moving Dashboard ===&lt;br /&gt;
Dashboards can be moved by dragging them with a mouse from the right side list to the target project in the left side hierarchy. Alternatively, dashboards to be moved can be selected and from the context menu, select &#039;&#039;&#039;Move to&#039;&#039;&#039; and then select the target project.&lt;br /&gt;
&lt;br /&gt;
=== Duplicating Dashboard ===&lt;br /&gt;
# Select the project where the dashboard to be duplicated is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Dashboards&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the dashboard to be duplicated.&lt;br /&gt;
# Click the &#039;&#039;&#039;Duplicate&#039;&#039;&#039; button. A duplicate of the dashboard is created.&lt;br /&gt;
&lt;br /&gt;
=== Importing Dashboard ===&lt;br /&gt;
Dashboards can be exported and imported as .qprpa files containing the dashboard structure (e.g., charts with their settings) without the actual data. A single .qprpa file can contain several dashboards.&lt;br /&gt;
&lt;br /&gt;
When dashboards are imported, the selected model will be set for the imported dashboards. Note also that when exporting and imported dashboards, the filter rules are preserved but the stored filter is lost (because the .qprpa files don&#039;t contain stored filters).&lt;br /&gt;
&lt;br /&gt;
Dashboard file can be imported if it has been exported using same or earlier QPR ProcessAnalyzer version. If the dashboard was exported using later version, it might not be possible to import it, if the dashboard structure supported by QPR ProcessAnalyzer has been improved between the versions.&lt;br /&gt;
&lt;br /&gt;
To import dashboards from a file:&lt;br /&gt;
# From the left side projects hierarchy, select the project where you want to import the dashboard(s).&lt;br /&gt;
# Open the &#039;&#039;&#039;Dashboards&#039;&#039;&#039; tab.&lt;br /&gt;
# In the header, select a model that will be used for the imported dashboards.&lt;br /&gt;
# Click the &#039;&#039;&#039;New&#039;&#039;&#039; button, and select &#039;&#039;&#039;Import Dashboard&#039;&#039;&#039;.&lt;br /&gt;
# Select a &#039;&#039;&#039;.qprpa file&#039;&#039;&#039; to be imported.&lt;br /&gt;
# Dashboards are imported, after which they appear as selected.&lt;br /&gt;
&lt;br /&gt;
=== Exporting Dashboard ===&lt;br /&gt;
Dashboards can be exported to a .qprpa file, and the same file can contain several dashboards. Dashboards can be exported as follows:&lt;br /&gt;
# Navigate to the project where the dashboard(s) to be exported are located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Dashboards&#039;&#039;&#039; tab and select the dashboard(s).&lt;br /&gt;
# Click the &#039;&#039;&#039;Export&#039;&#039;&#039; button. The file can is stored to disk.&lt;br /&gt;
&lt;br /&gt;
== Models ==&lt;br /&gt;
&#039;&#039;&#039;Models&#039;&#039;&#039; tab shows all models in the selected project. Models can be opened, new created, edited, deleted, imported and exported (you can go through an end-to-end instructions how to [[Creating_Process_Mining_Model|create model from eventlog data from a CSV file]]).&lt;br /&gt;
&lt;br /&gt;
Model status is shown as an icon left of the model name, indicating the type and validity of the model (and for in-memory models whether the model is in the server memory or being loaded into memory). Models have the following statuses:&lt;br /&gt;
* &#039;&#039;&#039;Case-centric model&#039;&#039;&#039;: Model is a valid case-centric Snowflake model.&lt;br /&gt;
* &#039;&#039;&#039;Object-centric model&#039;&#039;&#039;: Model is a valid object-centric Snowflake model.&lt;br /&gt;
* &#039;&#039;&#039;Online&#039;&#039;&#039; (for in-memory models): Model is currently in the memory and available to dashboards and analyses. Applicable only for in-memory models.&lt;br /&gt;
* &#039;&#039;&#039;Offline&#039;&#039;&#039; (for in-memory models):  Model is currently not the memory (and thus it&#039;s not consuming any memory resources). Applicable only for in-memory models.&lt;br /&gt;
* &#039;&#039;&#039;Loading&#039;&#039;&#039; (for in-memory models): Model is currently being loaded into the memory. The loading needs to complete until the model can be used. Applicable only for in-memory models.&lt;br /&gt;
* (no icon): When no icon is shown, datasource for the model hasn&#039;t been defined and the model cannot be used. To define the datasource, open the [[#Editing_Model_Settings|model properties]] and configure the events and cases datasources.&lt;br /&gt;
&lt;br /&gt;
The memory capacity of the server limits how many in-memory models there can be in the memory at the same time. Also loading a model into memory might take a while depending the model size. Note that in QPR ProcessAnalyzer, all processing is performed in the server/cloud side, so the model does not need to be loaded into user workstation, and thus it doesn&#039;t consume resources in the workstation side.&lt;br /&gt;
&lt;br /&gt;
=== Opening Model ===&lt;br /&gt;
# Select the project where the model to be opened is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Models&#039;&#039;&#039; tab.&lt;br /&gt;
# Double-click the model in the list, or select the model with a single click and click the &#039;&#039;&#039;Open&#039;&#039;&#039; button. Model is opened in the [[Navigation_Menu#Process_Discovery|Process Discovery]] view.&lt;br /&gt;
&lt;br /&gt;
=== Editing Model Settings ===&lt;br /&gt;
Model level settings are organized into following dialogs: Properties (general settings), Attributes, Notifications and Business calendar. Most settings can be changed while the model is in the memory, but changing datasource related settings and attribute settings will drop the model from the memory.&lt;br /&gt;
# Select the project where the model is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Models&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the model and select one of the following options: &#039;&#039;&#039;Properties&#039;&#039;&#039;, &#039;&#039;&#039;Attributes&#039;&#039;&#039;, &#039;&#039;&#039;Notifications&#039;&#039;&#039; or &#039;&#039;&#039;Business Calendar&#039;&#039;&#039;.&lt;br /&gt;
# After viewing or editing properties, close the dialog by clicking &#039;&#039;&#039;OK&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
See more about model settings:&lt;br /&gt;
* [[Business_Calendar|Business calendar]] (both Snowflake and in-memory models)&lt;br /&gt;
* [[Calculated_Attributes_in_QPR_ProcessAnalyzer|Calculated case and event attributes]] (only for in-memory models)&lt;br /&gt;
* [[Email_Notifications|Email notifications]] (only for in-memory models)&lt;br /&gt;
* [[Case_Level_Permissions|Case level permissions]] (only for in-memory models)&lt;br /&gt;
&lt;br /&gt;
=== Hiding Object Count Statistics ===&lt;br /&gt;
To help optimize the model for performance, it&#039;s possible to hide the object count statistics information in dropdown menus. To do this:&lt;br /&gt;
# Select the project where the model is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Models&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the model and select &#039;&#039;&#039;Properties&#039;&#039;&#039;.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;Details&#039;&#039;&#039; tab.&lt;br /&gt;
# Remove the selection from &#039;&#039;&#039;Show Object Count Statistics&#039;&#039;&#039;.&lt;br /&gt;
The Show Object Count Statistics setting can be overridden in [[Chart_On-screen_Settings#Configuration|Chart On-screen Settings]].&lt;br /&gt;
&lt;br /&gt;
=== Change Snowflake Warehouse for Model===&lt;br /&gt;
The Snowflake warehouse can be specified for a specific model. When defined, all queries for that model originating from dashboards use the specified warehouse instead of the (default) warehouse from the [[PA_Configuration_database_table#SnowflakeConnectionString|Snowflake connection string]]. You can use smaller warehouse for smaller models, and a larger warehouse for large models, to optimize costs and achieve similar performance for different sizes of models. When leaving the model&#039;s warehouse setting empty, the default warehouse in the Snowflake connection string will be used.&lt;br /&gt;
&lt;br /&gt;
A good practice is to use a smaller Snowflake warehouse as the default warehouse, and specify a larger warehouse for specific models that need it due to performance. Note that different warehouses should not be used unnecessarily because a common warehouse used by multiple models serves as a shared resource for all the usage which may be more cost effective than using different warehouses.&lt;br /&gt;
&lt;br /&gt;
Note that the Snowflake user used by QPR ProcessAnalyzer to access Snowflake needs to have permissions to use the specified warehouse. If there are no permissions or the specified warehouse doesn&#039;t exist in the Snowflake account, there will be an error message: &amp;quot;No active warehouse selected in the current session. Select an active warehouse with the &#039;use warehouse&#039; command.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Model&#039;s warehouse can be changed as follows:&lt;br /&gt;
# Select the project where the model is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Models&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the desired model and press the &#039;&#039;&#039;Properties&#039;&#039;&#039; button.&lt;br /&gt;
# The model properties dialog opens. In the &#039;&#039;&#039;Overview&#039;&#039;&#039; tab, specify the name of the Snowflake warehouse to the &#039;&#039;&#039;Snowflake Warehouse&#039;&#039;&#039; field.&lt;br /&gt;
# Press the &#039;&#039;&#039;Save&#039;&#039;&#039; button to close the dialog.&lt;br /&gt;
&lt;br /&gt;
=== Loading, Dropping and Reloading Model (in-memory only) ===&lt;br /&gt;
This functionality is only available for in-memory models.&lt;br /&gt;
# Select the project where the model is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Models&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the model and select one of the following options:&lt;br /&gt;
#*&#039;&#039;&#039;Load&#039;&#039;&#039; to start loading the model into memory. This option is available when the model is &#039;&#039;offline&#039;&#039;.&lt;br /&gt;
#*&#039;&#039;&#039;Drop&#039;&#039;&#039; to drop the model from the memory (for example to free memory resources). This option is available when the model is &#039;&#039;online&#039;&#039; or &#039;&#039;loading&#039;&#039;.&lt;br /&gt;
#*&#039;&#039;&#039;Reload&#039;&#039;&#039; to reload the model into the memory (i.e. drop and immediately start loading). Reloading is needed in order to get the latest data into the model after new data is imported to datatables. This option is available when the model is &#039;&#039;online&#039;&#039; or &#039;&#039;loading&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Creating Model ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where you want to create the model.&lt;br /&gt;
# Open the &#039;&#039;&#039;Models&#039;&#039;&#039; tab.&lt;br /&gt;
# Click the &#039;&#039;&#039;New&#039;&#039;&#039; button and click &#039;&#039;&#039;Model&#039;&#039;&#039;. Define a name for the model and click &#039;&#039;&#039;Create&#039;&#039;&#039;. Note that model names must be unique within a project.&lt;br /&gt;
&lt;br /&gt;
Note that each model in the same project needs to have a unique name.&lt;br /&gt;
&lt;br /&gt;
=== Deleting Model ===&lt;br /&gt;
When a model is deleted, it&#039;s not permanently removed, and can be recovered from the [[#Recycle_Bin|bin]]. Note that possible datatables used by the deleted models, are not deleted. Note also that the currently selected model cannot be deleted.&lt;br /&gt;
&lt;br /&gt;
Steps to delete models:&lt;br /&gt;
# Select the project where the model(s) to be deleted are located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Models&#039;&#039;&#039; tab.&lt;br /&gt;
# Select one or several models to be deleted.&lt;br /&gt;
# Click the &#039;&#039;&#039;Delete&#039;&#039;&#039; button and click &#039;&#039;&#039;Delete&#039;&#039;&#039; to the confirmation message.&lt;br /&gt;
&lt;br /&gt;
=== Renaming Model ===&lt;br /&gt;
# Select the project where the model to be renamed is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Models&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the model to be renamed.&lt;br /&gt;
# Click the &#039;&#039;&#039;Rename&#039;&#039;&#039; button.&lt;br /&gt;
# Change the model name in the opening dialog and click &#039;&#039;&#039;OK&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Moving Model ===&lt;br /&gt;
Models can be moved by dragging them with a mouse from the right side list to the target project in the left side hierarchy. Alternatively, models to be moved can be selected, from the context menu select &#039;&#039;&#039;Move to&#039;&#039;&#039; and then select the target project.&lt;br /&gt;
&lt;br /&gt;
=== Duplicating Model ===&lt;br /&gt;
Steps to duplicate a model:&lt;br /&gt;
# Select the project where the model to be duplicated is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Models&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the model to be duplicated.&lt;br /&gt;
# Click the &#039;&#039;&#039;Duplicate&#039;&#039;&#039; button. A duplicate of the model is created.&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* When a model is duplicated, datatables used by the model, are not duplicated. Thus, the duplicate model will refer to the same datatables as the original model. Datatables can be duplicated separately if desired.&lt;br /&gt;
* The model may contain [[Filtering_in_QPR_ProcessAnalyzer|filters]] which are duplicated with the model. Only those filters that the user making the duplicate can see, are duplicated.&lt;br /&gt;
&lt;br /&gt;
=== Importing Model ===&lt;br /&gt;
Models can be imported in .pacm and .xes formats. Importing a file creates a new model, so it&#039;s not possible to import data to an existing model.&lt;br /&gt;
&lt;br /&gt;
Steps to import model:&lt;br /&gt;
# From the left side projects hierarchy select the project where you want to import the model.&lt;br /&gt;
# Open the &#039;&#039;&#039;Models&#039;&#039;&#039; tab.&lt;br /&gt;
# Click the &#039;&#039;&#039;New&#039;&#039;&#039; button, and select &#039;&#039;&#039;Import Model&#039;&#039;&#039;.&lt;br /&gt;
# Select a .pacm or .xes file to be imported.&lt;br /&gt;
&lt;br /&gt;
=== Exporting Model ===&lt;br /&gt;
Models can be exported to a .pacm file (QPR ProcessAnalyzer compressed model file) to easily move models between QPR ProcessAnalyzer environments. The file contains all the eventlog data and also all model related settings. Steps to export:&lt;br /&gt;
# Navigate to the project where the model to be exported is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Models&#039;&#039;&#039; tab and select the model.&lt;br /&gt;
# Click the &#039;&#039;&#039;Export&#039;&#039;&#039; button. The exported file can be downloaded.&lt;br /&gt;
&lt;br /&gt;
=== Validating Model ===&lt;br /&gt;
Models can be validated to check they are technically valid. If a model is invalid, depending on the issue, it either cannot be used, or alternatively, it can be used but should not be used because calculation results may be incorrect. For Snowflake models, the model validation requires to run queries in Snowflake.&lt;br /&gt;
&lt;br /&gt;
To validate a model:&lt;br /&gt;
# Select the project where the model to be validated is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Models&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the model to be validated.&lt;br /&gt;
# Click the &#039;&#039;&#039;Validate&#039;&#039;&#039; button.&lt;br /&gt;
# Validation results are shown. If the model is invalid, a reason description for the invalidity is shown.&lt;br /&gt;
&lt;br /&gt;
== Datatables ==&lt;br /&gt;
&#039;&#039;&#039;Datatables&#039;&#039;&#039; can store any kind of tabular data in QPR ProcessAnalyzer. Datatables containing events and cases data can be selected as the events and cases datasource for a model. Datatables can also be used in the scripts. Datatables can be created, moved and deleted in the &#039;&#039;&#039;Datatables&#039;&#039;&#039; tab, which shows all datatables in the selected project.&lt;br /&gt;
&lt;br /&gt;
Datatables can be stored in Snowflake or SQL Server. For Snowflake datatables, the calculation is also performed in the Snowflake (in a virtual warehouse). Datatables storing data in SQL Server can be used as the in-memory models (loaded into QPR ProcessAnalyzer server memory). Snowflake datatables can be distinguished in the Workspace by the snowflake icon (left of the datatable name). If both SQL Server and Snowflake connections are available, the datasource needs to be selected when creating a datatable.&lt;br /&gt;
&lt;br /&gt;
Datatable names need to be unique within a project. Datatables stored to SQL Server have the following limitations: Maximum number of columns in a datatable is &#039;&#039;&#039;300&#039;&#039;&#039;, and maximum string length that can be stored into a datatable cell is &#039;&#039;&#039;4000&#039;&#039;&#039; characters.&lt;br /&gt;
&lt;br /&gt;
=== Opening Datatable ===&lt;br /&gt;
Datatable contents can be viewed as follows:&lt;br /&gt;
# On the left side projects hierarchy, select the project where the datatable to be opened is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Datatables&#039;&#039;&#039; tab.&lt;br /&gt;
# Double-click the datatable in the list, or select the datatable with a single click and click the &#039;&#039;&#039;Open&#039;&#039;&#039; button.&lt;br /&gt;
# If you want to change the shown information, click the &#039;&#039;&#039;Settings&#039;&#039;&#039; button and edit the settings.&lt;br /&gt;
# The dialog can be closed by clicking &#039;&#039;&#039;Close&#039;&#039;&#039; button.&lt;br /&gt;
&lt;br /&gt;
Following settings are available:&lt;br /&gt;
* Visible columns can be removed and changed in the &#039;&#039;&#039;Columns&#039;&#039;&#039; tab.&lt;br /&gt;
* Number of shows row can be changed.&lt;br /&gt;
* Sorting of the data can be changed.&lt;br /&gt;
* Dimensioning can be taken into use which will show the &#039;&#039;&#039;Measures&#039;&#039;&#039; tab (for more information, see the [[QPR_ProcessAnalyzer_Chart#Introduction|chart]].&lt;br /&gt;
* Datatable can be exported as an .xlsx or .csv file.&lt;br /&gt;
&lt;br /&gt;
=== Changing Datatable Properties ===&lt;br /&gt;
Datatable properties can be viewed and edited in the [[Datatable_Properties_Dialog|Datatable properties dialog]] that can be opened by selecting a datatable and clicking &#039;&#039;&#039;Properties&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Creating Datatable ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where you want to create a datatable.&lt;br /&gt;
# Open the &#039;&#039;&#039;Datatables&#039;&#039;&#039; tab.&lt;br /&gt;
# Click the &#039;&#039;&#039;New&#039;&#039;&#039; button and click &#039;&#039;&#039;Datatable&#039;&#039;&#039;.&lt;br /&gt;
# Define &#039;&#039;&#039;Name&#039;&#039;&#039; for the datatable. Note that datatable names must be unique within the project.&lt;br /&gt;
# Define the &#039;&#039;&#039;Datasource&#039;&#039;&#039; for the datatable as either &#039;&#039;&#039;Snowflake&#039;&#039;&#039; (for storing and processing data in Snowflake) or &#039;&#039;&#039;Local&#039;&#039;&#039; (for storing data in SQL Server and processing in-memory). If either the [[Snowflake Connection Configuration|Snowflake]] or  [[PA_Configuration_database_table#SqlServerConnectionString|SQL Server storage]] is not available, this selection is not available and the datatable will be created to the location that is available. If neither are available, datatables cannot be created.&lt;br /&gt;
# Click &#039;&#039;&#039;Create&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Note that each datatable in the same project needs to have a unique name.&lt;br /&gt;
&lt;br /&gt;
=== Importing Data to Datatable from CSV File ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where the target datatable is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Datatables&#039;&#039;&#039; tab, and select the datatable where to import data.&lt;br /&gt;
# Click the &#039;&#039;&#039;Import&#039;&#039;&#039; button, and select the CSV file to be imported.&lt;br /&gt;
# Check the suggested data type and conversion settings for the columns, and adjust them if needed. You can import data to the existing datatable columns, new datatable columns, or ignore individual CSV file columns in the import (see: [[Importing_Data_to_Datatable_from_CSV_File|CSV file import]]).&lt;br /&gt;
# Click &#039;&#039;&#039;Start import&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Refreshing Datatable from Datasource ===&lt;br /&gt;
When a database table behind a datatable is changed, the datatable needs to be refreshed from the datasource (such as Snowflake) to get the data current status to QPR ProcessAnalyzer. Typically the refresh is done after ETL run to load new data has completed. The refresh is the same operation is [[Datatable_in_Expression_Language#Datatable_Functions|Synchronize]] in the expression language.&lt;br /&gt;
&lt;br /&gt;
Refresh can be done as follows in the UI:&lt;br /&gt;
# Select the project where the datatable(s) to be refreshed are located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Datatables&#039;&#039;&#039; tab.&lt;br /&gt;
# Select one or several datatables to be refreshed.&lt;br /&gt;
# Click the &#039;&#039;&#039;Refresh from datasource&#039;&#039;&#039; button.&lt;br /&gt;
&lt;br /&gt;
=== Deleting Datatable ===&lt;br /&gt;
# Select the project where the datatable(s) to be deleted are located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Datatables&#039;&#039;&#039; tab.&lt;br /&gt;
# Select one or several datatables to be deleted.&lt;br /&gt;
# Click the &#039;&#039;&#039;Delete datatable&#039;&#039;&#039; button and click &#039;&#039;&#039;Delete&#039;&#039;&#039; to the confirmation message.&lt;br /&gt;
&lt;br /&gt;
=== Deleting Datatable Rows ===&lt;br /&gt;
When a datatable rows are deleted, the datatable itself is preserved including its columns (column names and data types). Datatable rows can be deleted, e.g., when importing the data again from a CSV file.&lt;br /&gt;
&lt;br /&gt;
Datatable rows can be deleted as follows:&lt;br /&gt;
# Select the project where the datatable(s) where to delete rows are located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Datatables&#039;&#039;&#039; tab.&lt;br /&gt;
# Select one or several datatables to be deleted.&lt;br /&gt;
# Click the &#039;&#039;&#039;Delete all rows&#039;&#039;&#039; button and click &#039;&#039;&#039;Delete&#039;&#039;&#039; to the confirmation message.&lt;br /&gt;
&lt;br /&gt;
=== Renaming Datatable ===&lt;br /&gt;
# Select the project where the datatable to be renamed is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Datatables&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the datatable to be renamed.&lt;br /&gt;
# Click the &#039;&#039;&#039;Rename&#039;&#039;&#039; button.&lt;br /&gt;
# Change the datatable name in the opening dialog and click &#039;&#039;&#039;OK&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Moving Datatable ===&lt;br /&gt;
Datatables can be moved by dragging them with a mouse from the right side list to the target project in the left side hierarchy. Alternatively, datatables to be moved can be selected, from the context menu select &#039;&#039;&#039;Move to&#039;&#039;&#039; and then select the target project.&lt;br /&gt;
&lt;br /&gt;
=== Duplicating Datatable ===&lt;br /&gt;
Datatable duplication (copying) creates a full copy of the datatable where also the data contents is duplicated. If the datatable contains lot of data, duplicating the data might take some time. Copying the data from the original datatable to the new datatable is performed in the background, so the user doesn&#039;t need to wait for it. Note that during the data copying, the workspace might temporarily show that the new datatable has less rows than the original.&lt;br /&gt;
&lt;br /&gt;
When duplicating a Snowflake datatable that uses a [[Datatable_Properties_Dialog#Data_location|custom table]], the duplicate datatable will refer to the same table in Snowflake (and not create a new table).&lt;br /&gt;
&lt;br /&gt;
# Select the project where the datatable to be duplicated is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Datatables&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the datatable to be duplicated.&lt;br /&gt;
# Click the &#039;&#039;&#039;Duplicate&#039;&#039;&#039; button. A duplicate of the datatable is created.&lt;br /&gt;
&lt;br /&gt;
== Data Schema ==&lt;br /&gt;
See [[Data Schema Dialog]].&lt;br /&gt;
&lt;br /&gt;
==  Bin ==&lt;br /&gt;
Deleted projects and models go to the &#039;&#039;&#039;Bin&#039;&#039;&#039;, where they can be either deleted forever or restored back into use. Purpose of the bin is that accidentally deleted items can still be restored. Note that currently dashboards, datatables and scripts don&#039;t go to the bin, but they are deleted forever right away. Note also that when a project is deleted (moved to the bin), also models in the project appear in the bin.&lt;br /&gt;
&lt;br /&gt;
The system administrators can see the bin and delete forever and restore projects and models.&lt;br /&gt;
&lt;br /&gt;
=== Emptying Bin ===&lt;br /&gt;
# Click &#039;&#039;&#039;Bin&#039;&#039;&#039; in the left side projects hierarchy.&lt;br /&gt;
# Click the &#039;&#039;&#039;Empty bin&#039;&#039;&#039; button on top right.&lt;br /&gt;
# Click &#039;&#039;&#039;Delete forever&#039;&#039;&#039; for the confirmation dialog.&lt;br /&gt;
&lt;br /&gt;
=== Deleting Items Forever ===&lt;br /&gt;
# Click &#039;&#039;&#039;Bin&#039;&#039;&#039; in the left side projects hierarchy.&lt;br /&gt;
# Select items in the bin that you want to delete forever.&lt;br /&gt;
# Click the &#039;&#039;&#039;Delete forever&#039;&#039;&#039; button.&lt;br /&gt;
# Click &#039;&#039;&#039;Delete forever&#039;&#039;&#039; for the confirmation dialog.&lt;br /&gt;
&lt;br /&gt;
=== Restoring Items ===&lt;br /&gt;
# Click &#039;&#039;&#039;Bin&#039;&#039;&#039; in the left side projects hierarchy.&lt;br /&gt;
# Select items in the bin that you want to restore.&lt;br /&gt;
# Click the &#039;&#039;&#039;Restore&#039;&#039;&#039; button.&lt;br /&gt;
&lt;br /&gt;
Selected items are restored to their original locations.&lt;br /&gt;
&lt;br /&gt;
[[Category: QPR ProcessAnalyzer]]&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=Managing_Scripts&amp;diff=28084</id>
		<title>Managing Scripts</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=Managing_Scripts&amp;diff=28084"/>
		<updated>2026-04-09T18:51:02Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63184&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In QPR ProcessAnalyzer, scripts can be used for ETL tasks and to automate routines. Scripts are managed in the [[QPR_ProcessAnalyzer_Project_Workspace|Project Workspace]].&lt;br /&gt;
&lt;br /&gt;
=== Running vs. Calling Scripts ===&lt;br /&gt;
&#039;&#039;Running&#039;&#039; a script means starting executing a stored script, which can be done in the UI or using the ScriptLauncher. A script can also &#039;&#039;call&#039;&#039; other scripts during the run. The differences between the running and calling are:&lt;br /&gt;
* Script can run only once at a time, whereas there are no limitations on how many times a script can be called at the same time&lt;br /&gt;
* Script log is written to the running script. No script log is written to the called script.&lt;br /&gt;
* Script status shows whether the script is being run or not. The status does not change, when a script is called from other script.&lt;br /&gt;
&lt;br /&gt;
When a script is running, it&#039;s not possible to start another run of the same script, so the first run needs to end to start new. Scripts can call other scripts and a called scripts can run multiple times simultaneously. In the stack of called scripts, the script log is generated to the top level script. Also the top level script shows that it&#039;s running and the called scripts do not.&lt;br /&gt;
&lt;br /&gt;
=== Scripts List ===&lt;br /&gt;
When selecting a project and opening the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab, all scripts in the project can be seen. Scripts list shows following information:&lt;br /&gt;
* &#039;&#039;&#039;Name&#039;&#039;&#039;: Name of the script.&lt;br /&gt;
* &#039;&#039;&#039;Status&#039;&#039;&#039;: Status of the script, which is one of following: &#039;&#039;Ready&#039;&#039;, &#039;&#039;Running&#039;&#039; or &#039;&#039;Stopping&#039;&#039;. For more information about script statuses, see below.&lt;br /&gt;
* &#039;&#039;&#039;Last run duration&#039;&#039;&#039;: Duration of the last ended run of the script (the last run result can be any).&lt;br /&gt;
* &#039;&#039;&#039;Last run date&#039;&#039;&#039;: Date and time when the last run ended. If you need to know the last run start time, subtract the &#039;&#039;Last run duration&#039;&#039; from this time.&lt;br /&gt;
* &#039;&#039;&#039;Last run result&#039;&#039;&#039;: Result of the last run of the script. Either of following: &#039;&#039;Completed&#039;&#039;, &#039;&#039;Failed&#039;&#039; or &#039;&#039;Aborted&#039;&#039;. For more information about last run results, see below.&lt;br /&gt;
* &#039;&#039;&#039;Id&#039;&#039;&#039;: Script id that uniquely identifies the script in the system.&lt;br /&gt;
&lt;br /&gt;
Scrips are in either of following statuses:&lt;br /&gt;
* &#039;&#039;&#039;Ready&#039;&#039;&#039;: Script is currently not running, and can be started.&lt;br /&gt;
* &#039;&#039;&#039;Running&#039;&#039;&#039;: Script is currently running, and the script can be stopped. When a script is running, another run of the same script cannot be started.&lt;br /&gt;
* &#039;&#039;&#039;Stopping&#039;&#039;&#039;: Script is currently being stopped. When a script is in this status, the script cannot be started nor stopped, so you need to wait for the script to stop. There may be a delay in stopping a script, depending on the operation currently performed by the script.&lt;br /&gt;
&lt;br /&gt;
The last script run result can be either of the following:&lt;br /&gt;
* &#039;&#039;&#039;Completed&#039;&#039;&#039;: The last run ended successfully, i.e. without any errors or exceptions. Note that despite of the technically successful run, the script might still not work as intended.&lt;br /&gt;
* &#039;&#039;&#039;Failed&#039;&#039;&#039;: The last run ended to an error or exception. To see more information about the reason of the failure, see the [[#Viewing_Script_Log|last run log]].&lt;br /&gt;
* &#039;&#039;&#039;Aborted&#039;&#039;&#039;: The last run was stopped by a user, so the script did not run till the end.&lt;br /&gt;
&lt;br /&gt;
=== Script Properties ===&lt;br /&gt;
To open Script Properties, &#039;&#039;&#039;right-click&#039;&#039;&#039; the script on the Scripts tab in the Workspace and select &#039;&#039;&#039;Properties&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
The Script Properties lists the following information on the &#039;&#039;&#039;General&#039;&#039;&#039; tab:&lt;br /&gt;
* &#039;&#039;&#039;Script ID&#039;&#039;&#039;: A unique ID in the system.&lt;br /&gt;
* &#039;&#039;&#039;Language&#039;&#039;&#039;: The script&#039;s language, either &amp;quot;SQL&amp;quot; or &amp;quot;Expression&amp;quot;.&lt;br /&gt;
* &#039;&#039;&#039;Status&#039;&#039;&#039;: As above in Scripts List.&lt;br /&gt;
* &#039;&#039;&#039;Last run start&#039;&#039;&#039;: Date and time when the last run started.&lt;br /&gt;
* &#039;&#039;&#039;Last run end&#039;&#039;&#039;: As &amp;quot;Last run date&amp;quot; above in Scripts List.&lt;br /&gt;
* &#039;&#039;&#039;Last run duration&#039;&#039;&#039;: As above in Scripts List.&lt;br /&gt;
* &#039;&#039;&#039;Last run result&#039;&#039;&#039;: As above in Scripts List.&lt;br /&gt;
* &#039;&#039;&#039;Last modified&#039;&#039;&#039;: Date and time when the script was last modified.&lt;br /&gt;
* &#039;&#039;&#039;Last modified by&#039;&#039;&#039;: User who last modified the script.&lt;br /&gt;
* &#039;&#039;&#039;Created&#039;&#039;&#039;: Date and time when the script was created.&lt;br /&gt;
* &#039;&#039;&#039;Created by&#039;&#039;&#039;: User who created the script.&lt;br /&gt;
&lt;br /&gt;
The Script Properties has the following information on the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab:&lt;br /&gt;
* &#039;&#039;&#039;MCP tool&#039;&#039;&#039;: A checkbox to select whether the script can be used as an [[QPR_ProcessAnalyzer_as_MCP_Server|MCP]] tool. Only System Administrators can modify this setting. Note that once a script has been defined as an MCP tool, only System Administrators are able to modify the script itself.&lt;br /&gt;
&lt;br /&gt;
The Script Properties has the following information on the &#039;&#039;&#039;Description&#039;&#039;&#039; tab:&lt;br /&gt;
* A textbox to edit the description of the script.&lt;br /&gt;
&lt;br /&gt;
=== Editing Script ===&lt;br /&gt;
Open the scripts editor as follows:&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and in the right-click context menu select &#039;&#039;&#039;Edit&#039;&#039;&#039;. Alternatively, you can hover the script and click the &#039;&#039;Edit&#039;&#039; button in the end of the row.&lt;br /&gt;
&lt;br /&gt;
If the script has been defined as an MCP tool, only System Administrators are able to edit the script.&lt;br /&gt;
&lt;br /&gt;
The script editor can show multiple scripts in the tabs, allowing to easily switch between the scrips. The editor remembers all scripts that have been opened during the session.&lt;br /&gt;
&lt;br /&gt;
In the script editor, you can:&lt;br /&gt;
* Run the script by clicking the &#039;&#039;&#039;Run&#039;&#039;&#039; button.&lt;br /&gt;
* Stop a running script by clicking the &#039;&#039;&#039;Stop&#039;&#039;&#039; button.&lt;br /&gt;
* Save a script having unsaved changes by clicking the &#039;&#039;&#039;Save&#039;&#039;&#039; button.&lt;br /&gt;
* To run a script having unsaved changes, click the &#039;&#039;&#039;Save and Run&#039;&#039;&#039; button. Note that the script needs to be saved to run it.&lt;br /&gt;
* To go back to the list of scripts, click the &#039;&#039;&#039;Go back&#039;&#039;&#039; button. If there are unsaved changes in any of the opened scripts, you need to either save or cancel the changes.&lt;br /&gt;
* To close a script, click the &#039;&#039;Close&#039;&#039; button for the tab showing the script. If there are unsaved changes, you need to either save or cancel changes.&lt;br /&gt;
&lt;br /&gt;
=== Starting Script ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and in the right-click context menu select &#039;&#039;&#039;Run&#039;&#039;&#039;. Alternatively, you can hover the script and click the &#039;&#039;Run&#039;&#039; button in the end of the row.&lt;br /&gt;
&lt;br /&gt;
Note that when running a script in the UI, the script must not contain commands where &#039;&#039;ExecuteInClientSide&#039;&#039; is enabled, because that is only supported when running scripts using [[QPR_ProcessAnalyzer_ScriptLauncher|QPR ScriptLauncher]].&lt;br /&gt;
&lt;br /&gt;
=== Stopping Script ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and from the right-click context menu select &#039;&#039;&#039;Stop&#039;&#039;&#039;. Alternatively, you can hover the script and click the &#039;&#039;Stop&#039;&#039; button in the end of the row.&lt;br /&gt;
&lt;br /&gt;
Note that it may take a while for a script to actually stop, depending on what kind of operation the script is executing when it&#039;s stopped.&lt;br /&gt;
&lt;br /&gt;
=== Viewing Script Log ===&lt;br /&gt;
It&#039;s possible to see the script log of the last run, and monitor the currently running script progress. Logs for older runs are not available in the UI, nut they are stored by the system.&lt;br /&gt;
&lt;br /&gt;
To see the logs:&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and in the right-click context menu select either &#039;&#039;&#039;View last run log&#039;&#039;&#039; or &#039;&#039;&#039;View current run log&#039;&#039;&#039;. (The script needs to be running to open the current run log.)&lt;br /&gt;
# If keeping the current run log open, the latest log entries are updated automatically every two seconds.&lt;br /&gt;
&lt;br /&gt;
More information about [[QPR_ProcessAnalyzer_Logs#Script_Log|Script Log]].&lt;br /&gt;
&lt;br /&gt;
=== Creating Script ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where you want to create a script.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Click the &#039;&#039;&#039;New&#039;&#039;&#039; button and click &#039;&#039;&#039;Script&#039;&#039;&#039;. Define a name for the script and the scripting &#039;&#039;&#039;Language&#039;&#039;&#039; (either &#039;&#039;&#039;Expression&#039;&#039;&#039; or &#039;&#039;&#039;SQL&#039;&#039;&#039;), and then click &#039;&#039;&#039;Create&#039;&#039;&#039;. Note that script names must be unique within a project.&lt;br /&gt;
&lt;br /&gt;
Note that the scripting language cannot be changed after the script has been created, so a new script needs to be created to change the language.&lt;br /&gt;
&lt;br /&gt;
Note that each script in the same project needs to have a unique name.&lt;br /&gt;
&lt;br /&gt;
=== Deleting Script ===&lt;br /&gt;
# Select the project where the script(s) to be deleted are located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select one or several scripts to be deleted.&lt;br /&gt;
# Click the &#039;&#039;&#039;Delete&#039;&#039;&#039; button and click &#039;&#039;&#039;Delete&#039;&#039;&#039; to the confirmation message.&lt;br /&gt;
&lt;br /&gt;
Note that if the script is being run, it cannot be deleted.&lt;br /&gt;
&lt;br /&gt;
=== Renaming Script ===&lt;br /&gt;
# Select the project where the script to be renamed is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script to be renamed.&lt;br /&gt;
# Click the &#039;&#039;&#039;Rename&#039;&#039;&#039; button.&lt;br /&gt;
# Change the script name in the opening dialog and click &#039;&#039;&#039;OK&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Moving Script ===&lt;br /&gt;
Scripts can be moved by dragging them with the left mouse button from the right side list to the target project in the left side hierarchy. Alternatively, you can first select the scripts, then from the right-click context menu select &#039;&#039;&#039;Move to&#039;&#039;&#039; and finally select the target project.&lt;br /&gt;
&lt;br /&gt;
=== Duplicating Script ===&lt;br /&gt;
# Select the project where the script to be duplicated is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script to be duplicated.&lt;br /&gt;
# Click the &#039;&#039;&#039;Duplicate&#039;&#039;&#039; button. A duplicate of the script is created.&lt;br /&gt;
&lt;br /&gt;
=== Viewing Script Run Results ===&lt;br /&gt;
Script runs can be [[Managing_Scripts#Running_Script|started]] and [[Managing_Scripts#Stopping_Script|stopped]] in the UI. Note that when running scripts using the UI, return values or results of the script cannot be viewed. If you want to use scripts that return data, there are following options:&lt;br /&gt;
* Script can write data to the script log&lt;br /&gt;
* Script can write data to a datatable&lt;br /&gt;
* Script can be called from a dashboard and use the dashboard to present the returned data (see more below).&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=Managing_Scripts&amp;diff=28083</id>
		<title>Managing Scripts</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=Managing_Scripts&amp;diff=28083"/>
		<updated>2026-04-09T18:50:06Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63184&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In QPR ProcessAnalyzer, scripts can be used for ETL tasks and to automate routines. Scripts are managed in the [[QPR_ProcessAnalyzer_Project_Workspace|Project Workspace]].&lt;br /&gt;
&lt;br /&gt;
=== Running vs. Calling Scripts ===&lt;br /&gt;
&#039;&#039;Running&#039;&#039; a script means starting executing a stored script, which can be done in the UI or using the ScriptLauncher. A script can also &#039;&#039;call&#039;&#039; other scripts during the run. The differences between the running and calling are:&lt;br /&gt;
* Script can run only once at a time, whereas there are no limitations on how many times a script can be called at the same time&lt;br /&gt;
* Script log is written to the running script. No script log is written to the called script.&lt;br /&gt;
* Script status shows whether the script is being run or not. The status does not change, when a script is called from other script.&lt;br /&gt;
&lt;br /&gt;
When a script is running, it&#039;s not possible to start another run of the same script, so the first run needs to end to start new. Scripts can call other scripts and a called scripts can run multiple times simultaneously. In the stack of called scripts, the script log is generated to the top level script. Also the top level script shows that it&#039;s running and the called scripts do not.&lt;br /&gt;
&lt;br /&gt;
=== Scripts List ===&lt;br /&gt;
When selecting a project and opening the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab, all scripts in the project can be seen. Scripts list shows following information:&lt;br /&gt;
* &#039;&#039;&#039;Name&#039;&#039;&#039;: Name of the script.&lt;br /&gt;
* &#039;&#039;&#039;Status&#039;&#039;&#039;: Status of the script, which is one of following: &#039;&#039;Ready&#039;&#039;, &#039;&#039;Running&#039;&#039; or &#039;&#039;Stopping&#039;&#039;. For more information about script statuses, see below.&lt;br /&gt;
* &#039;&#039;&#039;Last run duration&#039;&#039;&#039;: Duration of the last ended run of the script (the last run result can be any).&lt;br /&gt;
* &#039;&#039;&#039;Last run date&#039;&#039;&#039;: Date and time when the last run ended. If you need to know the last run start time, subtract the &#039;&#039;Last run duration&#039;&#039; from this time.&lt;br /&gt;
* &#039;&#039;&#039;Last run result&#039;&#039;&#039;: Result of the last run of the script. Either of following: &#039;&#039;Completed&#039;&#039;, &#039;&#039;Failed&#039;&#039; or &#039;&#039;Aborted&#039;&#039;. For more information about last run results, see below.&lt;br /&gt;
* &#039;&#039;&#039;Id&#039;&#039;&#039;: Script id that uniquely identifies the script in the system.&lt;br /&gt;
&lt;br /&gt;
Scrips are in either of following statuses:&lt;br /&gt;
* &#039;&#039;&#039;Ready&#039;&#039;&#039;: Script is currently not running, and can be started.&lt;br /&gt;
* &#039;&#039;&#039;Running&#039;&#039;&#039;: Script is currently running, and the script can be stopped. When a script is running, another run of the same script cannot be started.&lt;br /&gt;
* &#039;&#039;&#039;Stopping&#039;&#039;&#039;: Script is currently being stopped. When a script is in this status, the script cannot be started nor stopped, so you need to wait for the script to stop. There may be a delay in stopping a script, depending on the operation currently performed by the script.&lt;br /&gt;
&lt;br /&gt;
The last script run result can be either of the following:&lt;br /&gt;
* &#039;&#039;&#039;Completed&#039;&#039;&#039;: The last run ended successfully, i.e. without any errors or exceptions. Note that despite of the technically successful run, the script might still not work as intended.&lt;br /&gt;
* &#039;&#039;&#039;Failed&#039;&#039;&#039;: The last run ended to an error or exception. To see more information about the reason of the failure, see the [[#Viewing_Script_Log|last run log]].&lt;br /&gt;
* &#039;&#039;&#039;Aborted&#039;&#039;&#039;: The last run was stopped by a user, so the script did not run till the end.&lt;br /&gt;
&lt;br /&gt;
=== Script Properties ===&lt;br /&gt;
To open Script Properties, &#039;&#039;&#039;right-click&#039;&#039;&#039; the script on the Scripts tab in the Workspace and select &#039;&#039;&#039;Properties&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
The Script Properties lists the following information on the &#039;&#039;&#039;General&#039;&#039;&#039; tab:&lt;br /&gt;
* &#039;&#039;&#039;Script ID&#039;&#039;&#039;: A unique ID in the system.&lt;br /&gt;
* &#039;&#039;&#039;Language&#039;&#039;&#039;: The script&#039;s language, either &amp;quot;SQL&amp;quot; or &amp;quot;Expression&amp;quot;.&lt;br /&gt;
* &#039;&#039;&#039;Status&#039;&#039;&#039;: As above in Scripts List.&lt;br /&gt;
* &#039;&#039;&#039;Last run start&#039;&#039;&#039;: Date and time when the last run started.&lt;br /&gt;
* &#039;&#039;&#039;Last run end&#039;&#039;&#039;: As &amp;quot;Last run date&amp;quot; above in Scripts List.&lt;br /&gt;
* &#039;&#039;&#039;Last run duration&#039;&#039;&#039;: As above in Scripts List.&lt;br /&gt;
* &#039;&#039;&#039;Last run result&#039;&#039;&#039;: As above in Scripts List.&lt;br /&gt;
* &#039;&#039;&#039;Last modified&#039;&#039;&#039;: Date and time when the script was last modified.&lt;br /&gt;
* &#039;&#039;&#039;Last modified by&#039;&#039;&#039;: User who last modified the script.&lt;br /&gt;
* &#039;&#039;&#039;Created&#039;&#039;&#039;: Date and time when the script was created.&lt;br /&gt;
* &#039;&#039;&#039;Created by&#039;&#039;&#039;: User who created the script.&lt;br /&gt;
&lt;br /&gt;
The Script Properties has the following information on the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab:&lt;br /&gt;
* &#039;&#039;&#039;MCP tool&#039;&#039;&#039;: A checkbox to select whether the script can be used as an [[QPR_ProcessAnalyzer_as_MCP_Server|MCP]] tool. Only System Administrators can modify this setting. Note that once a script has been defined as an MCP tool, only System Administrators are able to modify the script itself.&lt;br /&gt;
&lt;br /&gt;
The Script Properties has the following information on the &#039;&#039;&#039;Description&#039;&#039;&#039; tab:&lt;br /&gt;
* A textbox to edit the description of the script.&lt;br /&gt;
&lt;br /&gt;
=== Editing Script ===&lt;br /&gt;
Open the scripts editor as follows:&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and in the right-click context menu select &#039;&#039;&#039;Edit&#039;&#039;&#039;. Alternatively, you can hover the script and click the &#039;&#039;Edit&#039;&#039; button in the end of the row.&lt;br /&gt;
&lt;br /&gt;
The script editor can show multiple scripts in the tabs, allowing to easily switch between the scrips. The editor remembers all scripts that have been opened during the session.&lt;br /&gt;
&lt;br /&gt;
In the script editor, you can:&lt;br /&gt;
* Run the script by clicking the &#039;&#039;&#039;Run&#039;&#039;&#039; button.&lt;br /&gt;
* Stop a running script by clicking the &#039;&#039;&#039;Stop&#039;&#039;&#039; button.&lt;br /&gt;
* Save a script having unsaved changes by clicking the &#039;&#039;&#039;Save&#039;&#039;&#039; button.&lt;br /&gt;
* To run a script having unsaved changes, click the &#039;&#039;&#039;Save and Run&#039;&#039;&#039; button. Note that the script needs to be saved to run it.&lt;br /&gt;
* To go back to the list of scripts, click the &#039;&#039;&#039;Go back&#039;&#039;&#039; button. If there are unsaved changes in any of the opened scripts, you need to either save or cancel the changes.&lt;br /&gt;
* To close a script, click the &#039;&#039;Close&#039;&#039; button for the tab showing the script. If there are unsaved changes, you need to either save or cancel changes.&lt;br /&gt;
&lt;br /&gt;
=== Starting Script ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and in the right-click context menu select &#039;&#039;&#039;Run&#039;&#039;&#039;. Alternatively, you can hover the script and click the &#039;&#039;Run&#039;&#039; button in the end of the row.&lt;br /&gt;
&lt;br /&gt;
Note that when running a script in the UI, the script must not contain commands where &#039;&#039;ExecuteInClientSide&#039;&#039; is enabled, because that is only supported when running scripts using [[QPR_ProcessAnalyzer_ScriptLauncher|QPR ScriptLauncher]].&lt;br /&gt;
&lt;br /&gt;
=== Stopping Script ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and from the right-click context menu select &#039;&#039;&#039;Stop&#039;&#039;&#039;. Alternatively, you can hover the script and click the &#039;&#039;Stop&#039;&#039; button in the end of the row.&lt;br /&gt;
&lt;br /&gt;
Note that it may take a while for a script to actually stop, depending on what kind of operation the script is executing when it&#039;s stopped.&lt;br /&gt;
&lt;br /&gt;
=== Viewing Script Log ===&lt;br /&gt;
It&#039;s possible to see the script log of the last run, and monitor the currently running script progress. Logs for older runs are not available in the UI, nut they are stored by the system.&lt;br /&gt;
&lt;br /&gt;
To see the logs:&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and in the right-click context menu select either &#039;&#039;&#039;View last run log&#039;&#039;&#039; or &#039;&#039;&#039;View current run log&#039;&#039;&#039;. (The script needs to be running to open the current run log.)&lt;br /&gt;
# If keeping the current run log open, the latest log entries are updated automatically every two seconds.&lt;br /&gt;
&lt;br /&gt;
More information about [[QPR_ProcessAnalyzer_Logs#Script_Log|Script Log]].&lt;br /&gt;
&lt;br /&gt;
=== Creating Script ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where you want to create a script.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Click the &#039;&#039;&#039;New&#039;&#039;&#039; button and click &#039;&#039;&#039;Script&#039;&#039;&#039;. Define a name for the script and the scripting &#039;&#039;&#039;Language&#039;&#039;&#039; (either &#039;&#039;&#039;Expression&#039;&#039;&#039; or &#039;&#039;&#039;SQL&#039;&#039;&#039;), and then click &#039;&#039;&#039;Create&#039;&#039;&#039;. Note that script names must be unique within a project.&lt;br /&gt;
&lt;br /&gt;
Note that the scripting language cannot be changed after the script has been created, so a new script needs to be created to change the language.&lt;br /&gt;
&lt;br /&gt;
Note that each script in the same project needs to have a unique name.&lt;br /&gt;
&lt;br /&gt;
=== Deleting Script ===&lt;br /&gt;
# Select the project where the script(s) to be deleted are located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select one or several scripts to be deleted.&lt;br /&gt;
# Click the &#039;&#039;&#039;Delete&#039;&#039;&#039; button and click &#039;&#039;&#039;Delete&#039;&#039;&#039; to the confirmation message.&lt;br /&gt;
&lt;br /&gt;
Note that if the script is being run, it cannot be deleted.&lt;br /&gt;
&lt;br /&gt;
=== Renaming Script ===&lt;br /&gt;
# Select the project where the script to be renamed is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script to be renamed.&lt;br /&gt;
# Click the &#039;&#039;&#039;Rename&#039;&#039;&#039; button.&lt;br /&gt;
# Change the script name in the opening dialog and click &#039;&#039;&#039;OK&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Moving Script ===&lt;br /&gt;
Scripts can be moved by dragging them with the left mouse button from the right side list to the target project in the left side hierarchy. Alternatively, you can first select the scripts, then from the right-click context menu select &#039;&#039;&#039;Move to&#039;&#039;&#039; and finally select the target project.&lt;br /&gt;
&lt;br /&gt;
=== Duplicating Script ===&lt;br /&gt;
# Select the project where the script to be duplicated is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script to be duplicated.&lt;br /&gt;
# Click the &#039;&#039;&#039;Duplicate&#039;&#039;&#039; button. A duplicate of the script is created.&lt;br /&gt;
&lt;br /&gt;
=== Viewing Script Run Results ===&lt;br /&gt;
Script runs can be [[Managing_Scripts#Running_Script|started]] and [[Managing_Scripts#Stopping_Script|stopped]] in the UI. Note that when running scripts using the UI, return values or results of the script cannot be viewed. If you want to use scripts that return data, there are following options:&lt;br /&gt;
* Script can write data to the script log&lt;br /&gt;
* Script can write data to a datatable&lt;br /&gt;
* Script can be called from a dashboard and use the dashboard to present the returned data (see more below).&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=PA_Configuration_database_table&amp;diff=28076</id>
		<title>PA Configuration database table</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=PA_Configuration_database_table&amp;diff=28076"/>
		<updated>2026-04-09T12:27:56Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63184&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer database has a configuration table &#039;&#039;&#039;PA_Configuration&#039;&#039;&#039; containing settings listed in the tables below. You need &#039;&#039;&#039;SQL Server Management Studio&#039;&#039;&#039; to edit the settings in the configuration table. QPR ProcessAnalyzer Server needs to be restarted (e.g. IIS application pool recycled) for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
For boolean values, &#039;&#039;true&#039;&#039; and &#039;&#039;1&#039;&#039; are valid values for yes, and &#039;&#039;false&#039;&#039; and &#039;&#039;0&#039;&#039; are valid for no.&lt;br /&gt;
&lt;br /&gt;
== General Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||DefaultDataSource&lt;br /&gt;
||&lt;br /&gt;
||Datasource where datatables data is stored when datatables are created by a script when the datasource is not explicitly specified in the script. Options are &#039;&#039;&#039;Snowflake&#039;&#039;&#039; and &#039;&#039;&#039;SqlServer&#039;&#039;&#039;. Value &#039;&#039;snowflake&#039;&#039; can be used when the &#039;&#039;SnowflakeConnectionString&#039;&#039; setting is defined, and value &#039;&#039;sqlserver&#039;&#039; can be used when the setting &#039;&#039;SqlServerConnectionString&#039;&#039; is configured. The setting can be changed without affecting the existing datatables, as the setting only affect new datatables. When this setting is empty, datatables are created in the metadata database.&lt;br /&gt;
|-&lt;br /&gt;
||SnowflakeConnectionString&lt;br /&gt;
||&lt;br /&gt;
||ODBC connection string for the Snowflake account. This setting is needed to make analytics calculations in the Snowflake. More information how to configure the [[Snowflake_Connection_Configuration#Set_Snowflake_ODBC_connection|Snowflake connection string]]. The Snowflake ODBC driver also needs to be installed in the machine running the QPR ProcessAnalyzer Server. When this setting has been configured, users can create Snowflake stored datatables and models using Snowflake calculation.&lt;br /&gt;
&lt;br /&gt;
When running QPR ProcessAnalyzer in the Snowpark Container Services, leave the SnowflakeConnectionString empty because then the connection string is created automatically using the method provided by the Snowpark Container Services.&lt;br /&gt;
|-&lt;br /&gt;
||SqlServerConnectionString&lt;br /&gt;
||&lt;br /&gt;
||Connection string for the SQL Server database containing the datatables data. It&#039;s recommended to use a separate database, but it&#039;s also possible to connect to the same database as the configuration data. If this setting is not configured, local datatables cannot be created (SQL Server stored). Existing datatables located in the configuration datatabase still work even if this setting has not be configured. Note that the connection uses ADO.Net (not ODBC), so the connection string is similar to the configuration database ([[Server_settings_in_appsettings.json|appsettings.json]] file).&lt;br /&gt;
|-&lt;br /&gt;
||DefaultColorPalette&lt;br /&gt;
||&lt;br /&gt;
||Charts color palette used globally in the environment. Defined as a json array of strings encoded with RGB hex (with or without alpha). Note that when a color palette in a chart has been changed, the chart starts using a chart-specific color palette, and the global color palette doesn&#039;t affect those charts. &lt;br /&gt;
&lt;br /&gt;
Example: [&amp;quot;#1F77B4&amp;quot;, &amp;quot;#FF7F0E&amp;quot;, &amp;quot;#2CA02C&amp;quot;, &amp;quot;#D62728&amp;quot;, &amp;quot;#9467BD&amp;quot;, &amp;quot;#8C564B&amp;quot;, &amp;quot;#E377C2&amp;quot;, &amp;quot;#7F7F7F&amp;quot;, &amp;quot;#BCBD22&amp;quot;, &amp;quot;#17BECF&amp;quot;]&lt;br /&gt;
|-&lt;br /&gt;
||OpenAIAPIKey&lt;br /&gt;
||&lt;br /&gt;
||API key for the OpenAI API (https://platform.openai.com/docs/api-reference). It needs to be configured to use the [[AI_Assistant_for_QPR_ProcessAnalyzer|AI Assistant]] and [[Generic_Functions_in_QPR_ProcessAnalyzer#OpenAIChatCompletion|OpenAIChatCompletion]] function.&lt;br /&gt;
|-&lt;br /&gt;
||OpenAIDefaultModelName&lt;br /&gt;
||gpt-4o&lt;br /&gt;
||OpenAI large language model (LLM) to use for the [[AI_Assistant_for_QPR_ProcessAnalyzer|AI Assistant]] and [[Generic_Functions_in_QPR_ProcessAnalyzer#OpenAIChatCompletion|OpenAIChatCompletion]] function. If not defined, &#039;&#039;&#039;gpt-4o&#039;&#039;&#039; will be used. Note that only LLM&#039;s that support the function calling feature, are suitable for the AI Assistant. More information about OpenAI models: https://platform.openai.com/docs/models.&lt;br /&gt;
|-&lt;br /&gt;
||DefaultCortexAgentsModelName&lt;br /&gt;
||llama3.1-70b&lt;br /&gt;
||Specifies the default language model when using Snowflake Cortex Agents (https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-agents-rest-api). If not defined, &#039;&#039;&#039;llama3.1-70b&#039;&#039;&#039; is used.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;QueryTimeout&amp;quot;&amp;gt;QueryTimeout&amp;lt;/span&amp;gt;&lt;br /&gt;
||300&lt;br /&gt;
||Timeout (in seconds) for requests made to /api/expression/query and /api/expression endpoints. When the timeout is exceeded, the query is stopped and a timeout error is returned. Purpose of the timeout is to protect the system against potentially too long running or even never-ending queries which might otherwise jam the system.&lt;br /&gt;
|-&lt;br /&gt;
||SessionIdleTimeout&lt;br /&gt;
||3600&lt;br /&gt;
||Idle user session expiration timeout in seconds. User session expires if the session hasn&#039;t been used after this amount of time.&lt;br /&gt;
|-&lt;br /&gt;
||SessionMaximumDuration&lt;br /&gt;
||86400&lt;br /&gt;
||Maximum duration for a user session in seconds. Even if a session is used so that the SessionIdleTimeout is not reached, the session is expired after this amount of time.&lt;br /&gt;
|-&lt;br /&gt;
|DatabaseId&lt;br /&gt;
|&lt;br /&gt;
||Unique identifier for the QPR ProcessAnalyzer environment. Any characters between a-z, A-Z, 0-9 and _ (underscore) can be used in the DatabaseId. If the DatabaseId is missing or set to null, the system will generate a new GUID during startup and use it as the DatabaseId. The DatabaseId can also be an empty string. If using several QPR ProcessAnalyzer environments, make sure each use a different DatabaseId. The DatabaseId is used as part of the table names in Snowflake and SQL Server (in the datatables database). Thus if the DatabaseId is changed, all tables in Snowflake and SQL Server named with qprpa_dt_&amp;lt;DatabaseId&amp;gt;_&amp;lt;DatatableId&amp;gt; need to be renamed.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;CacheOnlyPrimaryKeysForFilters&amp;quot;&amp;gt;CacheOnlyPrimaryKeysForFilters&amp;lt;/span&amp;gt;&lt;br /&gt;
||false&lt;br /&gt;
||Defines whether to include all columns in the Snowflake event cache filter tables (&#039;&#039;false&#039;&#039;), or only the primary key columns (&#039;&#039;true&#039;&#039;). When &#039;&#039;false&#039;&#039;, cache table creation is slower, but the analysis calculation is faster because the original event table is not used anymore. When &#039;&#039;false&#039;&#039;, also the cache tables require more storage space in Snowflake.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Localization Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||DefaultUiLanguage&lt;br /&gt;
||en_US&lt;br /&gt;
||Language code for the UI language that new user accounts get by default. Thus, a created user account has this language until the user changes her/his language. Also the login page is translated using this language when QPR ProcessAnalyzer is used for the first time in that web browser (when user has changed the language, it&#039;s remembered by the browser). This setting must be one of the supported language codes (xx_XX):&lt;br /&gt;
* English: &#039;&#039;&#039;en_US&#039;&#039;&#039;&lt;br /&gt;
* Finnish: &#039;&#039;&#039;fi_FI&#039;&#039;&#039;&lt;br /&gt;
* French: &#039;&#039;&#039;fr_FR&#039;&#039;&#039;&lt;br /&gt;
* German: &#039;&#039;&#039;de_DE&#039;&#039;&#039;&lt;br /&gt;
* Polish: &#039;&#039;&#039;pl_PL&#039;&#039;&#039;&lt;br /&gt;
* Portuguese: &#039;&#039;&#039;pt_BR&#039;&#039;&#039;&lt;br /&gt;
* Spanish: &#039;&#039;&#039;es_ES&#039;&#039;&#039;&lt;br /&gt;
* Swedish: &#039;&#039;&#039;sv_SE&#039;&#039;&#039;&lt;br /&gt;
* Ukrainian: &#039;&#039;&#039;uk_UK&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||DefaultDateFormat&lt;br /&gt;
||MM/dd/yyyy&lt;br /&gt;
||Default date format that new user accounts get by default. The date format does not contain the time part (e.g. hours, minutes and seconds). Defined using the .Net date format (https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings).&lt;br /&gt;
|-&lt;br /&gt;
||DefaultFirstDayOfWeek&lt;br /&gt;
||0&lt;br /&gt;
||Default first day of the week that new user accounts get by default. &#039;&#039;&#039;0&#039;&#039;&#039; is Sunday and &#039;&#039;&#039;1&#039;&#039;&#039; is Monday. This information is used by the UI when showing e.g. calendars.&lt;br /&gt;
|-&lt;br /&gt;
||DefaultUse12HourClock&lt;br /&gt;
||false&lt;br /&gt;
||Defines whether the 12-hour clock is used by default (instead of the 24-hour clock) for the new user accounts when showing time information in the UI. Defined as &#039;&#039;&#039;true&#039;&#039;&#039; or &#039;&#039;&#039;false&#039;&#039;&#039;. More information about the 12-hour clock: https://en.wikipedia.org/wiki/12-hour_clock.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== ETL Scripts Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||AllowExternalDatasources&lt;br /&gt;
||true&lt;br /&gt;
||Can be used to disallow all connections to external datasources in the expression language and SQL scripts to improve security. Disallowed operations include ODBC, OLE DB, SQL Server (Ado.Net), SAP, Salesforce, and call web service. Note that this setting does not prevent the Snowflake processing. Regardless of this setting, QPR ScriptLauncher can be used to extract data from source systems.&lt;br /&gt;
|-&lt;br /&gt;
||SandboxDatabaseConnectionString&lt;br /&gt;
||&lt;br /&gt;
||Connection string to scripting sandbox database (ETL). If not defined, SQL-based ETL scripts cannot be run. Connection string for the scripting sandbox database is similar to the  [[Server_settings_in_appsettings.json|QPR ProcessAnalyzer database connection string]]. More information: [[Setting up Scripting Sandbox]].&lt;br /&gt;
|-&lt;br /&gt;
||AllowNonTemporaryETLTargetTable&lt;br /&gt;
||false&lt;br /&gt;
||Defined whether ETL scripts are allowed to create global temporary database tables (tables starting with ##). More information about temporary tables: https://docs.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql?view=sql-server-ver15#temporary-tables.&lt;br /&gt;
|-&lt;br /&gt;
||DatabaseBulkCopyTimeout&lt;br /&gt;
||600&lt;br /&gt;
||Timeout used for data import operations to datatables.&lt;br /&gt;
|-&lt;br /&gt;
|SandboxDatabaseBulkCopyTimeout&lt;br /&gt;
||600&lt;br /&gt;
||Timeout used for data import operations to sandbox tables in the SQL scripts.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;DatabaseBulkCopyBatchSize&amp;lt;/span&amp;gt;&lt;br /&gt;
||5000&lt;br /&gt;
||BulkCopyBatchSize given for QPR ProcessAnalyzer database SqlBulkCopy operations.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;SandboxDatabaseBulkCopyBatchSize&amp;lt;/span&amp;gt;&lt;br /&gt;
||5000&lt;br /&gt;
||BulkCopyBatchSize given for sandbox SqlBulkCopy operations.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== In-memory Calculation Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||NumberOfParallelModelReaders&lt;br /&gt;
||4&lt;br /&gt;
||Models and datatable contents can be loaded with multiple simultaneous connections to the database to speed up the loading. This setting determines how many parallel loaders/readers at maximum (loaders are loading at the same time). For smaller models there are less parallel loaders than the defined limit: If there are less than 100000 rows in the table, there is only one loader. If there are less than 200000 rows in the table, there are only two loaders, and so on. &lt;br /&gt;
&lt;br /&gt;
The more there are parallel loaders, the more processor load and network bandwidth is consumed, and other operations in QPR ProcessAnalyzer might slow down. Note also that the performance optimum is achieved with a certain number of parallel loaders which differs between environment. Thus to achieve the best performance, data loading should be tested with different number of parallel loaders. Increasing number of parallel loaders beyond the optimum decreases the performance.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
||StartupModelLoadingMaxParallelism&lt;br /&gt;
||2&lt;br /&gt;
||Maximum number of QPR ProcessAnalyzer models that are loaded into memory simultaneously by the [[Automatic_Model_Loading_on_Server_Startup|Automatic Loading on Server Startup]]. If there are more models to be loaded on the server startup than this setting, loading for the rest of the models is started one by one when previous model loadings are completed. If this setting is not defined, &#039;&#039;&#039;2&#039;&#039;&#039; is used as a default value.&lt;br /&gt;
&lt;br /&gt;
Loading more models at the same time will speed up the whole model loading process, but on the other hand, it causes more load on the system, which affects the system responsiveness for users. Model loading consists of (1) transferring data from the datasource to QPR ProcessAnalyzer and (2) loaded data preprocessing into a model. The former uses mainly network bandwidth (if datasource is in a different server) and the latter uses mainly processor capacity in the QPR ProcessAnalyzer server. &lt;br /&gt;
&lt;br /&gt;
This setting affects only the model loading during the server startup and it doesn&#039;t restrict models loadings initiated by users.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== SAML 2.0 Federated Authentication Settings ==&lt;br /&gt;
Note that the SAMLMetadataUrl and ServiceProviderLocation are mandatory for the federated authentication to work. Having both ExternalOAuthServerConfiguration and SAML authentication configured at the same time is not supported.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||SAMLMetadataUrl&lt;br /&gt;
||&lt;br /&gt;
Metadata URL of the identity provider (IdP). Check that the metadata url can actually be opened using a web browser and is publicly available. The metadata is an XML document starting with &#039;&#039;&#039;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&#039;&#039;&#039; followed by an &#039;&#039;&#039;EntityDescriptor&#039;&#039;&#039; tag. The metadata URL might look &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;https://your.federated.identity.provider.com/saml/metadata&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;. This setting is mandatory for the SAML authentication to work.&lt;br /&gt;
|-&lt;br /&gt;
||ServiceProviderLocation&lt;br /&gt;
||&lt;br /&gt;
Specifies the QPR ProcessAnalyzer server location (the root path which contains e.g. the &#039;&#039;ui&#039;&#039; folder). It&#039;s used by the url to redirect back to QPR ProcessAnalyzer after a successful authentication from the identity provider. The setting is defined in the following form: &#039;&#039;&#039;https://&amp;lt;hostname&amp;gt;/qprpa&#039;&#039;&#039;, for example &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;https://customer.onqpr.com/qprpa&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;. Note that the actual redirect back url is &#039;&#039;&#039;https://&amp;lt;hostname&amp;gt;/qprpa/api/Saml2/Acs&#039;&#039;&#039; (/api/Saml2/Acs is automatically included to the url). This setting is mandatory for the SAML authentication to work. Note that if this reply url is configured the identity provider, it must match with the ServiceProviderLocation setting.&lt;br /&gt;
|-&lt;br /&gt;
||SAMLUserIdAttribute&lt;br /&gt;
||&lt;br /&gt;
Name of the SAML attribute in the assertion that will be used as the user&#039;s login name. If this field is not defined, the &#039;&#039;&#039;saml:Assertion&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:Subject&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:NameID&#039;&#039;&#039; attribute in the assertion is used. If this setting is given, one of the &#039;&#039;&#039;saml:Assertion&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:AttributeStatement&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:Attribute&#039;&#039;&#039; elements in the assertion is used (the &#039;&#039;&#039;Name&#039;&#039;&#039; attribute in the &#039;&#039;&#039;saml:Attribute&#039;&#039;&#039; element is used for matching). Please note that the saml:NameID element is different than the usual SAML attributes that are defined by the saml:Attribute elements. For example, if an email address is used as a user id, the value of the setting could be for example &#039;&#039;&amp;lt;nowiki&amp;gt;http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress&amp;lt;/nowiki&amp;gt;&#039;&#039;.&lt;br /&gt;
|-&lt;br /&gt;
||SAMLGroupsAttribute&lt;br /&gt;
||Attribute name in SAML assertion that is mapped to user groups in QPR ProcessAnalyzer. The user group names are case sensitive. When a user logs in, the user is added to and removed from groups based on the information in the SAML assertion. If this setting is not configured, users are not added to or removed from groups automatically. Note that the user needs to login for the groups to be synchronized. If a group doesn&#039;t exist in QPR ProcessAnalyzer, that group is skipped.&lt;br /&gt;
&lt;br /&gt;
In the SAML assertion, attributes are in the saml:Assertion &amp;gt; saml:AttributeStatement &amp;gt; saml:Attribute elements (the Name attribute in the saml:Attribute element is used for matching).&lt;br /&gt;
|-&lt;br /&gt;
||SAMLEncryptionCertificate&lt;br /&gt;
||This setting defines a PFX formatted X.509 certificate (defined in RCF 1422) used to encrypt SAML assertions. The public key of the certificate is published in the service provider metadata, where the identity provider can read it and encrypt SAML assertions. QPR ProcessAnalyzer as the service provider uses the corresponding private key of the certificate to decrypt SAML assertions. The setting needs to be a PFX formatted certificate file that is base64 encoded and it doesn&#039;t contain the BEGIN CERTIFICATE etc. header or footer lines. This setting is needed only when using the SAML assertions encryption. Even though this setting is defined, the SAML assertions are not required to be encrypted. More information how to create the certificate file (https://stackoverflow.com/questions/16480846/x-509-private-public-key) and convert it to base64 (https://stackoverflow.com/questions/46959822/base-64-encoded-form-of-the-pfx-file).&lt;br /&gt;
|-&lt;br /&gt;
||SAMLSigningCertificate&lt;br /&gt;
||This setting defines a PFX formatted X.509 certificate (defined in RCF 1422) used to sign SAML authentication requests sent from QPR ProcessAnalyzer to the identity provider. The public key of the certificate is published in the service provider metadata, where the identity provider can read it, to verify the authenticity of the SAML requests. The setting needs to be a PFX formatted certificate file that is base64 encoded and it doesn&#039;t contain the BEGIN CERTIFICATE etc. header or footer lines. If this setting is not defined, the internal hard-coded signing certificate is used. More information how to create the certificate file (https://stackoverflow.com/questions/16480846/x-509-private-public-key) and convert it to base64 (https://stackoverflow.com/questions/46959822/base-64-encoded-form-of-the-pfx-file).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OAuth 2.0 Authentication Settings ==&lt;br /&gt;
Having both ExternalOAuthServerConfiguration and SAML authentication configured at the same time is not supported.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||ExternalOAuthServerConfiguration&lt;br /&gt;
||Used to configure OAuth 2.0 compatible OAuth server settings for server that is used to authenticate the user signing in to ProcessAnalyzer. If not set, external OAuth server will not be used for authentication. If set, contains a string representation of a JSON object that supports the following properties:&lt;br /&gt;
* &#039;&#039;&#039;Authority&#039;&#039;&#039; (string): OAuth authority URL for authentication. E.g., https://accounts.google.com/&lt;br /&gt;
* &#039;&#039;&#039;Audience&#039;&#039;&#039; (string): Mandatory. OAuth audience/client ID for validating OAuth tokens.&lt;br /&gt;
* &#039;&#039;&#039;AuthorizeUrlOverride&#039;&#039;&#039; (string): Override URL for the OAuth authorization endpoint. If empty or not defined, the default URL from the authority&#039;s discovery document is used.&lt;br /&gt;
* &#039;&#039;&#039;TokenUrlOverride&#039;&#039;&#039; (string): Override URL for the OAuth token endpoint. If empty or not defined, the default URL from the authority&#039;s discovery document is used.&lt;br /&gt;
* &#039;&#039;&#039;UserInfoUrlOverride&#039;&#039;&#039; (string): Override URL to fetch user information from the OAuth provider. If empty or not defined, the default URL from the authority&#039;s discovery document is used. Should not be used if OpendID Connect is to be used as access token validation is skipped.&lt;br /&gt;
* &#039;&#039;&#039;ClientSecret&#039;&#039;&#039; (string): OAuth client secret for confidential client authentication. If configured, this value is sent as the client_secret parameter when exchanging authorization codes for tokens.&lt;br /&gt;
* &#039;&#039;&#039;Issuer&#039;&#039;&#039; (string): OAuth issuer for validating OAuth tokens. If empty, the authority URL&#039;s issuer is used.&lt;br /&gt;
* &#039;&#039;&#039;UserNameClaim&#039;&#039;&#039; (string): Name of the claim whose value is to be used as the name of the authenticated user. The default value is &amp;quot;preferred_username&amp;quot;.&lt;br /&gt;
* &#039;&#039;&#039;UserGroupsClaim&#039;&#039;&#039; (string): Name of the claim whose value is to be used as the names of the user groups the authenticated user belongs to. When a user logs in, the user is added to and removed from groups based on the information in the UserGroupsClaim. If this setting is not configured, users are not added to or removed from groups automatically. Note that the user needs to login for the groups to be synchronized. If a group doesn&#039;t exist in QPR ProcessAnalyzer, that group is skipped. The default value is empty, i.e. groups are not synchronized.&amp;lt;br&amp;gt;&lt;br /&gt;
Example configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Authority&amp;quot;: &amp;quot;https://accounts.google.com/&amp;quot;,&lt;br /&gt;
  &amp;quot;AuthorizeUrlOverride&amp;quot;: &amp;quot;https://accounts.google.com/o/oauth2/v2/auth&amp;quot;,&lt;br /&gt;
  &amp;quot;TokenUrlOverride&amp;quot;: &amp;quot;https://oauth2.googleapis.com/token&amp;quot;,&lt;br /&gt;
  &amp;quot;UserInfoUrlOverride&amp;quot;: &amp;quot;https://www.googleapis.com/oauth2/v3/userinfo&amp;quot;,&lt;br /&gt;
  &amp;quot;Audience&amp;quot;: &amp;quot;...&amp;quot;,&lt;br /&gt;
  &amp;quot;ClientSecret&amp;quot;: &amp;quot;...&amp;quot;,&lt;br /&gt;
  &amp;quot;UserNameClaim&amp;quot;: &amp;quot;name&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== SMTP Server Settings ==&lt;br /&gt;
SMTP server settings are needed for QPR ProcessAnalyzer to send email messages. Email sending is used by the [[Email_Notifications|notifications]] and the [[Generic_Functions_in_QPR_ProcessAnalyzer#SendEmail|SendEmail]] function in the expression language.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||SmtpServer&lt;br /&gt;
||DNS name, host name or IP address of the SMTP server. Mandatory setting for the email sending to work.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpPort&lt;br /&gt;
||TCP port number of the SMTP server. If not defined, port 25 is used by default.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpAuthenticationUsername&lt;br /&gt;
||User name for authenticating to the SMTP server. If not defined, no authentication is used to connect to the SMTP server.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpFromAddress&lt;br /&gt;
||Email address where email messages sent by QPR ProcessAnalyzer appear to be coming from. This doesn&#039;t need to be a real email address, although the address used may affect email spam filters. The setting configured here is the default email address to use in following cases:&lt;br /&gt;
* &#039;&#039;From address&#039;&#039; is not set for the email notifications&lt;br /&gt;
* &#039;&#039;From&#039;&#039; parameter is not defined for the expression language &#039;&#039;SendEmail&#039;&#039; function&lt;br /&gt;
* &#039;&#039;EmailFrom&#039;&#039; parameter is not defined for the SQL Scripting SendEmail operation&lt;br /&gt;
|-&lt;br /&gt;
||SmtpAuthenticationPassword&lt;br /&gt;
||Password for authenticating to the SMTP server.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpEnableSSL&lt;br /&gt;
||Use value &#039;&#039;&#039;True&#039;&#039;&#039; or &#039;&#039;&#039;False&#039;&#039;&#039; depending whether TLS connection to the SMTP server is used or not. If not defined, &#039;&#039;False&#039;&#039; is the default value.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MCP Server Settings ==&lt;br /&gt;
MCP server settings are needed for QPR ProcessAnalyzer to act as an [[QPR_ProcessAnalyzer_as_MCP_Server|MCP server]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||McpServerConfiguration&lt;br /&gt;
||Used to configure the MCP server built-in to ProcessAnalyzer server. If not set, MCP server functionality is disabled and MCP clients can&#039;t access to this server using MCP. If set, contains a string representation of a JSON object that supports the following properties:&lt;br /&gt;
* &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; (string): If defined and not empty, defines the API key that can be used to connect to QPR ProcessAnalyzer MCP server without any other authentication. Default value is empty.&amp;lt;br&amp;gt;&lt;br /&gt;
Example value when using API Key authentication:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{ &amp;quot;McpApiKey&amp;quot;: &amp;quot;xnTqr@Hd87JcuCmQZbjUHfwD@&amp;quot; }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Example value when using OAuth 2.0 authentication:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{ &amp;quot;McpApiKey&amp;quot;: null }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that when using OAuth 2.0 authentication the BuiltInOAuthServerConfiguration (see below) needs to be defined with an AcceptedAudiences value other than the default.&lt;br /&gt;
|-&lt;br /&gt;
||BuiltInOAuthServerConfiguration&lt;br /&gt;
||Used to configure OAuth 2.0 compatible OAuth server settings for OAuth server built-in to ProcessAnalyzer server. If not set, built-in OAuth server functionality is disabled and clients can&#039;t connect to this server using OAuth. If set, contains a string representation of a JSON object that supports the following properties: &lt;br /&gt;
* &#039;&#039;&#039;Issuer&#039;&#039;&#039; (string): OAuth issuer, which identifies a trusted authorization server that authenticates users and issues OAuth 2.0 access tokens and JSON Web Tokens (JWTs). If not defined or empty, default value is used, which is of format: &amp;lt;QPR ProcessAnalyzer server&#039;s base URL&amp;gt;/builtin-oauth. For example: https://example.com/builtin-oauth. The default value is empty.&lt;br /&gt;
* &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; (array of strings): Array of strings that define all the accepted audiences this QPR ProcessAnalyzer server is serving. When authorizing user using OAuth, these values are matched with the audience-parameter (a.k.a. client id) of the authorization. Only requests with a value that matches a value in this array are accepted. If null, audience-parameters are not validated at all. Instead, all authorization requests will pass the audience validation check. This also enables [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)]. The default value is an empty array.&lt;br /&gt;
* &#039;&#039;&#039;SigningKey&#039;&#039;&#039; (string): Signing key for the built-in OAuth identity provider. If empty, generates a non-deterministic key based on the physical system where QPR ProcessAnalyzer is running. NOTE: Once QPR ProcessAnalyzer server is restarted, these non-deterministic keys no longer work. If defined, string must contain the key either in PEM ([https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rsa.importfrompem?view=net-10.0 RFC 7468 PEM-encoded key]) or JSON ([https://datatracker.ietf.org/doc/html/rfc7517 RFC 7517]) format. The default value is empty.&lt;br /&gt;
* &#039;&#039;&#039;TokenLifetimeSeconds&#039;&#039;&#039; (integer): Token lifetime in seconds for the built-in OAuth identity provider. After access token created by built-in gets older than this lifetime, it becomes unusable and a new token has to be created. The default value is 3600.&lt;br /&gt;
* &#039;&#039;&#039;DisableExternalOAuthForwarding&#039;&#039;&#039; (boolean): Can be used to disable forwarding OAuth requests to any configured external OAuth authorization server or SAML identity provider. If set, a QPR ProcessAnalyzer&#039;s own login view functionality is always used when authorizing a user. The default value is false.&lt;br /&gt;
Example configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Issuer&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
  &amp;quot;AcceptedAudiences&amp;quot;: [&amp;quot;qpr-processanalyzer&amp;quot;],&lt;br /&gt;
  &amp;quot;SigningKey&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
  &amp;quot;TokenLifetime&amp;quot;: 3600&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Readonly Information ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;DatabaseVersion&amp;lt;/span&amp;gt;&lt;br /&gt;
||Database schema version. It will be updated automatically when the newer version of QPR ProcessAnalyzer Server connects to the database and performs migration for the database schema.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;InitializationScriptDatabaseVersion&amp;lt;/span&amp;gt;&lt;br /&gt;
||Database version that was when the database was initialized when the software was installed. Do not change this setting.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;MinimumDatabaseVersion&amp;lt;/span&amp;gt;&lt;br /&gt;
||Minimum allowed database version for QPR ProcessAnalyzer Server connecting to the database. This is a legacy setting and it should not be used.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=PA_Configuration_database_table&amp;diff=28075</id>
		<title>PA Configuration database table</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=PA_Configuration_database_table&amp;diff=28075"/>
		<updated>2026-04-09T12:24:10Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63184&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer database has a configuration table &#039;&#039;&#039;PA_Configuration&#039;&#039;&#039; containing settings listed in the tables below. You need &#039;&#039;&#039;SQL Server Management Studio&#039;&#039;&#039; to edit the settings in the configuration table. QPR ProcessAnalyzer Server needs to be restarted (e.g. IIS application pool recycled) for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
For boolean values, &#039;&#039;true&#039;&#039; and &#039;&#039;1&#039;&#039; are valid values for yes, and &#039;&#039;false&#039;&#039; and &#039;&#039;0&#039;&#039; are valid for no.&lt;br /&gt;
&lt;br /&gt;
== General Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||DefaultDataSource&lt;br /&gt;
||&lt;br /&gt;
||Datasource where datatables data is stored when datatables are created by a script when the datasource is not explicitly specified in the script. Options are &#039;&#039;&#039;Snowflake&#039;&#039;&#039; and &#039;&#039;&#039;SqlServer&#039;&#039;&#039;. Value &#039;&#039;snowflake&#039;&#039; can be used when the &#039;&#039;SnowflakeConnectionString&#039;&#039; setting is defined, and value &#039;&#039;sqlserver&#039;&#039; can be used when the setting &#039;&#039;SqlServerConnectionString&#039;&#039; is configured. The setting can be changed without affecting the existing datatables, as the setting only affect new datatables. When this setting is empty, datatables are created in the metadata database.&lt;br /&gt;
|-&lt;br /&gt;
||SnowflakeConnectionString&lt;br /&gt;
||&lt;br /&gt;
||ODBC connection string for the Snowflake account. This setting is needed to make analytics calculations in the Snowflake. More information how to configure the [[Snowflake_Connection_Configuration#Set_Snowflake_ODBC_connection|Snowflake connection string]]. The Snowflake ODBC driver also needs to be installed in the machine running the QPR ProcessAnalyzer Server. When this setting has been configured, users can create Snowflake stored datatables and models using Snowflake calculation.&lt;br /&gt;
&lt;br /&gt;
When running QPR ProcessAnalyzer in the Snowpark Container Services, leave the SnowflakeConnectionString empty because then the connection string is created automatically using the method provided by the Snowpark Container Services.&lt;br /&gt;
|-&lt;br /&gt;
||SqlServerConnectionString&lt;br /&gt;
||&lt;br /&gt;
||Connection string for the SQL Server database containing the datatables data. It&#039;s recommended to use a separate database, but it&#039;s also possible to connect to the same database as the configuration data. If this setting is not configured, local datatables cannot be created (SQL Server stored). Existing datatables located in the configuration datatabase still work even if this setting has not be configured. Note that the connection uses ADO.Net (not ODBC), so the connection string is similar to the configuration database ([[Server_settings_in_appsettings.json|appsettings.json]] file).&lt;br /&gt;
|-&lt;br /&gt;
||DefaultColorPalette&lt;br /&gt;
||&lt;br /&gt;
||Charts color palette used globally in the environment. Defined as a json array of strings encoded with RGB hex (with or without alpha). Note that when a color palette in a chart has been changed, the chart starts using a chart-specific color palette, and the global color palette doesn&#039;t affect those charts. &lt;br /&gt;
&lt;br /&gt;
Example: [&amp;quot;#1F77B4&amp;quot;, &amp;quot;#FF7F0E&amp;quot;, &amp;quot;#2CA02C&amp;quot;, &amp;quot;#D62728&amp;quot;, &amp;quot;#9467BD&amp;quot;, &amp;quot;#8C564B&amp;quot;, &amp;quot;#E377C2&amp;quot;, &amp;quot;#7F7F7F&amp;quot;, &amp;quot;#BCBD22&amp;quot;, &amp;quot;#17BECF&amp;quot;]&lt;br /&gt;
|-&lt;br /&gt;
||OpenAIAPIKey&lt;br /&gt;
||&lt;br /&gt;
||API key for the OpenAI API (https://platform.openai.com/docs/api-reference). It needs to be configured to use the [[AI_Assistant_for_QPR_ProcessAnalyzer|AI Assistant]] and [[Generic_Functions_in_QPR_ProcessAnalyzer#OpenAIChatCompletion|OpenAIChatCompletion]] function.&lt;br /&gt;
|-&lt;br /&gt;
||OpenAIDefaultModelName&lt;br /&gt;
||gpt-4o&lt;br /&gt;
||OpenAI large language model (LLM) to use for the [[AI_Assistant_for_QPR_ProcessAnalyzer|AI Assistant]] and [[Generic_Functions_in_QPR_ProcessAnalyzer#OpenAIChatCompletion|OpenAIChatCompletion]] function. If not defined, &#039;&#039;&#039;gpt-4o&#039;&#039;&#039; will be used. Note that only LLM&#039;s that support the function calling feature, are suitable for the AI Assistant. More information about OpenAI models: https://platform.openai.com/docs/models.&lt;br /&gt;
|-&lt;br /&gt;
||DefaultCortexAgentsModelName&lt;br /&gt;
||llama3.1-70b&lt;br /&gt;
||Specifies the default language model when using Snowflake Cortex Agents (https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-agents-rest-api). If not defined, &#039;&#039;&#039;llama3.1-70b&#039;&#039;&#039; is used.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;QueryTimeout&amp;quot;&amp;gt;QueryTimeout&amp;lt;/span&amp;gt;&lt;br /&gt;
||300&lt;br /&gt;
||Timeout (in seconds) for requests made to /api/expression/query and /api/expression endpoints. When the timeout is exceeded, the query is stopped and a timeout error is returned. Purpose of the timeout is to protect the system against potentially too long running or even never-ending queries which might otherwise jam the system.&lt;br /&gt;
|-&lt;br /&gt;
||SessionIdleTimeout&lt;br /&gt;
||3600&lt;br /&gt;
||Idle user session expiration timeout in seconds. User session expires if the session hasn&#039;t been used after this amount of time.&lt;br /&gt;
|-&lt;br /&gt;
||SessionMaximumDuration&lt;br /&gt;
||86400&lt;br /&gt;
||Maximum duration for a user session in seconds. Even if a session is used so that the SessionIdleTimeout is not reached, the session is expired after this amount of time.&lt;br /&gt;
|-&lt;br /&gt;
|DatabaseId&lt;br /&gt;
|&lt;br /&gt;
||Unique identifier for the QPR ProcessAnalyzer environment. Any characters between a-z, A-Z, 0-9 and _ (underscore) can be used in the DatabaseId. If the DatabaseId is missing or set to null, the system will generate a new GUID during startup and use it as the DatabaseId. The DatabaseId can also be an empty string. If using several QPR ProcessAnalyzer environments, make sure each use a different DatabaseId. The DatabaseId is used as part of the table names in Snowflake and SQL Server (in the datatables database). Thus if the DatabaseId is changed, all tables in Snowflake and SQL Server named with qprpa_dt_&amp;lt;DatabaseId&amp;gt;_&amp;lt;DatatableId&amp;gt; need to be renamed.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;CacheOnlyPrimaryKeysForFilters&amp;quot;&amp;gt;CacheOnlyPrimaryKeysForFilters&amp;lt;/span&amp;gt;&lt;br /&gt;
||false&lt;br /&gt;
||Defines whether to include all columns in the Snowflake event cache filter tables (&#039;&#039;false&#039;&#039;), or only the primary key columns (&#039;&#039;true&#039;&#039;). When &#039;&#039;false&#039;&#039;, cache table creation is slower, but the analysis calculation is faster because the original event table is not used anymore. When &#039;&#039;false&#039;&#039;, also the cache tables require more storage space in Snowflake.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Localization Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||DefaultUiLanguage&lt;br /&gt;
||en_US&lt;br /&gt;
||Language code for the UI language that new user accounts get by default. Thus, a created user account has this language until the user changes her/his language. Also the login page is translated using this language when QPR ProcessAnalyzer is used for the first time in that web browser (when user has changed the language, it&#039;s remembered by the browser). This setting must be one of the supported language codes (xx_XX):&lt;br /&gt;
* English: &#039;&#039;&#039;en_US&#039;&#039;&#039;&lt;br /&gt;
* Finnish: &#039;&#039;&#039;fi_FI&#039;&#039;&#039;&lt;br /&gt;
* French: &#039;&#039;&#039;fr_FR&#039;&#039;&#039;&lt;br /&gt;
* German: &#039;&#039;&#039;de_DE&#039;&#039;&#039;&lt;br /&gt;
* Polish: &#039;&#039;&#039;pl_PL&#039;&#039;&#039;&lt;br /&gt;
* Portuguese: &#039;&#039;&#039;pt_BR&#039;&#039;&#039;&lt;br /&gt;
* Spanish: &#039;&#039;&#039;es_ES&#039;&#039;&#039;&lt;br /&gt;
* Swedish: &#039;&#039;&#039;sv_SE&#039;&#039;&#039;&lt;br /&gt;
* Ukrainian: &#039;&#039;&#039;uk_UK&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||DefaultDateFormat&lt;br /&gt;
||MM/dd/yyyy&lt;br /&gt;
||Default date format that new user accounts get by default. The date format does not contain the time part (e.g. hours, minutes and seconds). Defined using the .Net date format (https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings).&lt;br /&gt;
|-&lt;br /&gt;
||DefaultFirstDayOfWeek&lt;br /&gt;
||0&lt;br /&gt;
||Default first day of the week that new user accounts get by default. &#039;&#039;&#039;0&#039;&#039;&#039; is Sunday and &#039;&#039;&#039;1&#039;&#039;&#039; is Monday. This information is used by the UI when showing e.g. calendars.&lt;br /&gt;
|-&lt;br /&gt;
||DefaultUse12HourClock&lt;br /&gt;
||false&lt;br /&gt;
||Defines whether the 12-hour clock is used by default (instead of the 24-hour clock) for the new user accounts when showing time information in the UI. Defined as &#039;&#039;&#039;true&#039;&#039;&#039; or &#039;&#039;&#039;false&#039;&#039;&#039;. More information about the 12-hour clock: https://en.wikipedia.org/wiki/12-hour_clock.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== ETL Scripts Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||AllowExternalDatasources&lt;br /&gt;
||true&lt;br /&gt;
||Can be used to disallow all connections to external datasources in the expression language and SQL scripts to improve security. Disallowed operations include ODBC, OLE DB, SQL Server (Ado.Net), SAP, Salesforce, and call web service. Note that this setting does not prevent the Snowflake processing. Regardless of this setting, QPR ScriptLauncher can be used to extract data from source systems.&lt;br /&gt;
|-&lt;br /&gt;
||SandboxDatabaseConnectionString&lt;br /&gt;
||&lt;br /&gt;
||Connection string to scripting sandbox database (ETL). If not defined, SQL-based ETL scripts cannot be run. Connection string for the scripting sandbox database is similar to the  [[Server_settings_in_appsettings.json|QPR ProcessAnalyzer database connection string]]. More information: [[Setting up Scripting Sandbox]].&lt;br /&gt;
|-&lt;br /&gt;
||AllowNonTemporaryETLTargetTable&lt;br /&gt;
||false&lt;br /&gt;
||Defined whether ETL scripts are allowed to create global temporary database tables (tables starting with ##). More information about temporary tables: https://docs.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql?view=sql-server-ver15#temporary-tables.&lt;br /&gt;
|-&lt;br /&gt;
||DatabaseBulkCopyTimeout&lt;br /&gt;
||600&lt;br /&gt;
||Timeout used for data import operations to datatables.&lt;br /&gt;
|-&lt;br /&gt;
|SandboxDatabaseBulkCopyTimeout&lt;br /&gt;
||600&lt;br /&gt;
||Timeout used for data import operations to sandbox tables in the SQL scripts.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;DatabaseBulkCopyBatchSize&amp;lt;/span&amp;gt;&lt;br /&gt;
||5000&lt;br /&gt;
||BulkCopyBatchSize given for QPR ProcessAnalyzer database SqlBulkCopy operations.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;SandboxDatabaseBulkCopyBatchSize&amp;lt;/span&amp;gt;&lt;br /&gt;
||5000&lt;br /&gt;
||BulkCopyBatchSize given for sandbox SqlBulkCopy operations.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== In-memory Calculation Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||NumberOfParallelModelReaders&lt;br /&gt;
||4&lt;br /&gt;
||Models and datatable contents can be loaded with multiple simultaneous connections to the database to speed up the loading. This setting determines how many parallel loaders/readers at maximum (loaders are loading at the same time). For smaller models there are less parallel loaders than the defined limit: If there are less than 100000 rows in the table, there is only one loader. If there are less than 200000 rows in the table, there are only two loaders, and so on. &lt;br /&gt;
&lt;br /&gt;
The more there are parallel loaders, the more processor load and network bandwidth is consumed, and other operations in QPR ProcessAnalyzer might slow down. Note also that the performance optimum is achieved with a certain number of parallel loaders which differs between environment. Thus to achieve the best performance, data loading should be tested with different number of parallel loaders. Increasing number of parallel loaders beyond the optimum decreases the performance.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
||StartupModelLoadingMaxParallelism&lt;br /&gt;
||2&lt;br /&gt;
||Maximum number of QPR ProcessAnalyzer models that are loaded into memory simultaneously by the [[Automatic_Model_Loading_on_Server_Startup|Automatic Loading on Server Startup]]. If there are more models to be loaded on the server startup than this setting, loading for the rest of the models is started one by one when previous model loadings are completed. If this setting is not defined, &#039;&#039;&#039;2&#039;&#039;&#039; is used as a default value.&lt;br /&gt;
&lt;br /&gt;
Loading more models at the same time will speed up the whole model loading process, but on the other hand, it causes more load on the system, which affects the system responsiveness for users. Model loading consists of (1) transferring data from the datasource to QPR ProcessAnalyzer and (2) loaded data preprocessing into a model. The former uses mainly network bandwidth (if datasource is in a different server) and the latter uses mainly processor capacity in the QPR ProcessAnalyzer server. &lt;br /&gt;
&lt;br /&gt;
This setting affects only the model loading during the server startup and it doesn&#039;t restrict models loadings initiated by users.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== SAML 2.0 Federated Authentication Settings ==&lt;br /&gt;
Note that the SAMLMetadataUrl and ServiceProviderLocation are mandatory for the federated authentication to work. Having both ExternalOAuthServerConfiguration and SAML authentication configured at the same time is not supported.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||SAMLMetadataUrl&lt;br /&gt;
||&lt;br /&gt;
Metadata URL of the identity provider (IdP). Check that the metadata url can actually be opened using a web browser and is publicly available. The metadata is an XML document starting with &#039;&#039;&#039;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&#039;&#039;&#039; followed by an &#039;&#039;&#039;EntityDescriptor&#039;&#039;&#039; tag. The metadata URL might look &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;https://your.federated.identity.provider.com/saml/metadata&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;. This setting is mandatory for the SAML authentication to work.&lt;br /&gt;
|-&lt;br /&gt;
||ServiceProviderLocation&lt;br /&gt;
||&lt;br /&gt;
Specifies the QPR ProcessAnalyzer server location (the root path which contains e.g. the &#039;&#039;ui&#039;&#039; folder). It&#039;s used by the url to redirect back to QPR ProcessAnalyzer after a successful authentication from the identity provider. The setting is defined in the following form: &#039;&#039;&#039;https://&amp;lt;hostname&amp;gt;/qprpa&#039;&#039;&#039;, for example &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;https://customer.onqpr.com/qprpa&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;. Note that the actual redirect back url is &#039;&#039;&#039;https://&amp;lt;hostname&amp;gt;/qprpa/api/Saml2/Acs&#039;&#039;&#039; (/api/Saml2/Acs is automatically included to the url). This setting is mandatory for the SAML authentication to work. Note that if this reply url is configured the identity provider, it must match with the ServiceProviderLocation setting.&lt;br /&gt;
|-&lt;br /&gt;
||SAMLUserIdAttribute&lt;br /&gt;
||&lt;br /&gt;
Name of the SAML attribute in the assertion that will be used as the user&#039;s login name. If this field is not defined, the &#039;&#039;&#039;saml:Assertion&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:Subject&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:NameID&#039;&#039;&#039; attribute in the assertion is used. If this setting is given, one of the &#039;&#039;&#039;saml:Assertion&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:AttributeStatement&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:Attribute&#039;&#039;&#039; elements in the assertion is used (the &#039;&#039;&#039;Name&#039;&#039;&#039; attribute in the &#039;&#039;&#039;saml:Attribute&#039;&#039;&#039; element is used for matching). Please note that the saml:NameID element is different than the usual SAML attributes that are defined by the saml:Attribute elements. For example, if an email address is used as a user id, the value of the setting could be for example &#039;&#039;&amp;lt;nowiki&amp;gt;http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress&amp;lt;/nowiki&amp;gt;&#039;&#039;.&lt;br /&gt;
|-&lt;br /&gt;
||SAMLGroupsAttribute&lt;br /&gt;
||Attribute name in SAML assertion that is mapped to user groups in QPR ProcessAnalyzer. The user group names are case sensitive. When a user logs in, the user is added to and removed from groups based on the information in the SAML assertion. If this setting is not configured, users are not added to or removed from groups automatically. Note that the user needs to login for the groups to be synchronized. If a group doesn&#039;t exist in QPR ProcessAnalyzer, that group is skipped.&lt;br /&gt;
&lt;br /&gt;
In the SAML assertion, attributes are in the saml:Assertion &amp;gt; saml:AttributeStatement &amp;gt; saml:Attribute elements (the Name attribute in the saml:Attribute element is used for matching).&lt;br /&gt;
|-&lt;br /&gt;
||SAMLEncryptionCertificate&lt;br /&gt;
||This setting defines a PFX formatted X.509 certificate (defined in RCF 1422) used to encrypt SAML assertions. The public key of the certificate is published in the service provider metadata, where the identity provider can read it and encrypt SAML assertions. QPR ProcessAnalyzer as the service provider uses the corresponding private key of the certificate to decrypt SAML assertions. The setting needs to be a PFX formatted certificate file that is base64 encoded and it doesn&#039;t contain the BEGIN CERTIFICATE etc. header or footer lines. This setting is needed only when using the SAML assertions encryption. Even though this setting is defined, the SAML assertions are not required to be encrypted. More information how to create the certificate file (https://stackoverflow.com/questions/16480846/x-509-private-public-key) and convert it to base64 (https://stackoverflow.com/questions/46959822/base-64-encoded-form-of-the-pfx-file).&lt;br /&gt;
|-&lt;br /&gt;
||SAMLSigningCertificate&lt;br /&gt;
||This setting defines a PFX formatted X.509 certificate (defined in RCF 1422) used to sign SAML authentication requests sent from QPR ProcessAnalyzer to the identity provider. The public key of the certificate is published in the service provider metadata, where the identity provider can read it, to verify the authenticity of the SAML requests. The setting needs to be a PFX formatted certificate file that is base64 encoded and it doesn&#039;t contain the BEGIN CERTIFICATE etc. header or footer lines. If this setting is not defined, the internal hard-coded signing certificate is used. More information how to create the certificate file (https://stackoverflow.com/questions/16480846/x-509-private-public-key) and convert it to base64 (https://stackoverflow.com/questions/46959822/base-64-encoded-form-of-the-pfx-file).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OAuth 2.0 Authentication Settings ==&lt;br /&gt;
Having both ExternalOAuthServerConfiguration and SAML authentication configured at the same time is not supported.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||ExternalOAuthServerConfiguration&lt;br /&gt;
||Used to configure OAuth 2.0 compatible OAuth server settings for server that is used to authenticate the user signing in to ProcessAnalyzer. If not set, external OAuth server will not be used for authentication. If set, contains a string representation of a JSON object that supports the following properties:&lt;br /&gt;
* &#039;&#039;&#039;Authority&#039;&#039;&#039; (string): OAuth authority URL for authentication. E.g., https://accounts.google.com/&lt;br /&gt;
* &#039;&#039;&#039;Audience&#039;&#039;&#039; (string): Mandatory. OAuth audience/client ID for validating OAuth tokens.&lt;br /&gt;
* &#039;&#039;&#039;AuthorizeUrlOverride&#039;&#039;&#039; (string): Override URL for the OAuth authorization endpoint. If empty or not defined, the default URL from the authority&#039;s discovery document is used.&lt;br /&gt;
* &#039;&#039;&#039;TokenUrlOverride&#039;&#039;&#039; (string): Override URL for the OAuth token endpoint. If empty or not defined, the default URL from the authority&#039;s discovery document is used.&lt;br /&gt;
* &#039;&#039;&#039;UserInfoUrlOverride&#039;&#039;&#039; (string): Override URL to fetch user information from the OAuth provider. If empty or not defined, the default URL from the authority&#039;s discovery document is used. Should not be used if OpendID Connect is to be used as access token validation is skipped.&lt;br /&gt;
* &#039;&#039;&#039;ClientSecret&#039;&#039;&#039; (string): OAuth client secret for confidential client authentication. If configured, this value is sent as the client_secret parameter when exchanging authorization codes for tokens.&lt;br /&gt;
* &#039;&#039;&#039;Issuer&#039;&#039;&#039; (string): OAuth issuer for validating OAuth tokens. If empty, the authority URL&#039;s issuer is used.&lt;br /&gt;
* &#039;&#039;&#039;UserNameClaim&#039;&#039;&#039; (string): Name of the claim whose value is to be used as the name of the authenticated user. The default value is &amp;quot;preferred_username&amp;quot;.&lt;br /&gt;
* &#039;&#039;&#039;UserGroupsClaim&#039;&#039;&#039; (string): Name of the claim whose value is to be used as the names of the user groups the authenticated user belongs to. When a user logs in, the user is added to and removed from groups based on the information in the UserGroupsClaim. If this setting is not configured, users are not added to or removed from groups automatically. Note that the user needs to login for the groups to be synchronized. If a group doesn&#039;t exist in QPR ProcessAnalyzer, that group is skipped. The default value is empty, i.e. groups are not synchronized.&amp;lt;br&amp;gt;&lt;br /&gt;
Example configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Authority&amp;quot;: &amp;quot;https://accounts.google.com/&amp;quot;,&lt;br /&gt;
  &amp;quot;AuthorizeUrlOverride&amp;quot;: &amp;quot;https://accounts.google.com/o/oauth2/v2/auth&amp;quot;,&lt;br /&gt;
  &amp;quot;TokenUrlOverride&amp;quot;: &amp;quot;https://oauth2.googleapis.com/token&amp;quot;,&lt;br /&gt;
  &amp;quot;UserInfoUrlOverride&amp;quot;: &amp;quot;https://www.googleapis.com/oauth2/v3/userinfo&amp;quot;,&lt;br /&gt;
  &amp;quot;Audience&amp;quot;: &amp;quot;...&amp;quot;,&lt;br /&gt;
  &amp;quot;ClientSecret&amp;quot;: &amp;quot;...&amp;quot;,&lt;br /&gt;
  &amp;quot;UserNameClaim&amp;quot;: &amp;quot;name&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== SMTP Server Settings ==&lt;br /&gt;
SMTP server settings are needed for QPR ProcessAnalyzer to send email messages. Email sending is used by the [[Email_Notifications|notifications]] and the [[Generic_Functions_in_QPR_ProcessAnalyzer#SendEmail|SendEmail]] function in the expression language.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||SmtpServer&lt;br /&gt;
||DNS name, host name or IP address of the SMTP server. Mandatory setting for the email sending to work.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpPort&lt;br /&gt;
||TCP port number of the SMTP server. If not defined, port 25 is used by default.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpAuthenticationUsername&lt;br /&gt;
||User name for authenticating to the SMTP server. If not defined, no authentication is used to connect to the SMTP server.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpFromAddress&lt;br /&gt;
||Email address where email messages sent by QPR ProcessAnalyzer appear to be coming from. This doesn&#039;t need to be a real email address, although the address used may affect email spam filters. The setting configured here is the default email address to use in following cases:&lt;br /&gt;
* &#039;&#039;From address&#039;&#039; is not set for the email notifications&lt;br /&gt;
* &#039;&#039;From&#039;&#039; parameter is not defined for the expression language &#039;&#039;SendEmail&#039;&#039; function&lt;br /&gt;
* &#039;&#039;EmailFrom&#039;&#039; parameter is not defined for the SQL Scripting SendEmail operation&lt;br /&gt;
|-&lt;br /&gt;
||SmtpAuthenticationPassword&lt;br /&gt;
||Password for authenticating to the SMTP server.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpEnableSSL&lt;br /&gt;
||Use value &#039;&#039;&#039;True&#039;&#039;&#039; or &#039;&#039;&#039;False&#039;&#039;&#039; depending whether TLS connection to the SMTP server is used or not. If not defined, &#039;&#039;False&#039;&#039; is the default value.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MCP Server Settings ==&lt;br /&gt;
MCP server settings are needed for QPR ProcessAnalyzer to act as an [[QPR_ProcessAnalyzer_as_MCP_Server|MCP server]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||McpServerConfiguration&lt;br /&gt;
||Used to configure the MCP server built-in to ProcessAnalyzer server. If not set, MCP server functionality is disabled and MCP clients can&#039;t access to this server using MCP. If set, contains a string representation of a JSON object that supports the following properties:&lt;br /&gt;
* &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; (string): If defined and not empty, defines the API key that can be used to connect to QPR ProcessAnalyzer MCP server without any other authentication. Default value is empty.&amp;lt;br&amp;gt;&lt;br /&gt;
Example value when using API Key authentication:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{ &amp;quot;McpApiKey&amp;quot;: &amp;quot;xnTqr@Hd87JcuCmQZbjUHfwD@&amp;quot; }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
||BuiltInOAuthServerConfiguration&lt;br /&gt;
||Used to configure OAuth 2.0 compatible OAuth server settings for OAuth server built-in to ProcessAnalyzer server. If not set, built-in OAuth server functionality is disabled and clients can&#039;t connect to this server using OAuth. If set, contains a string representation of a JSON object that supports the following properties: &lt;br /&gt;
* &#039;&#039;&#039;Issuer&#039;&#039;&#039; (string): OAuth issuer, which identifies a trusted authorization server that authenticates users and issues OAuth 2.0 access tokens and JSON Web Tokens (JWTs). If not defined or empty, default value is used, which is of format: &amp;lt;QPR ProcessAnalyzer server&#039;s base URL&amp;gt;/builtin-oauth. For example: https://example.com/builtin-oauth. The default value is empty.&lt;br /&gt;
* &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; (array of strings): Array of strings that define all the accepted audiences this QPR ProcessAnalyzer server is serving. When authorizing user using OAuth, these values are matched with the audience-parameter (a.k.a. client id) of the authorization. Only requests with a value that matches a value in this array are accepted. If null, audience-parameters are not validated at all. Instead, all authorization requests will pass the audience validation check. This also enables [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)]. The default value is an empty array.&lt;br /&gt;
* &#039;&#039;&#039;SigningKey&#039;&#039;&#039; (string): Signing key for the built-in OAuth identity provider. If empty, generates a non-deterministic key based on the physical system where QPR ProcessAnalyzer is running. NOTE: Once QPR ProcessAnalyzer server is restarted, these non-deterministic keys no longer work. If defined, string must contain the key either in PEM ([https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rsa.importfrompem?view=net-10.0 RFC 7468 PEM-encoded key]) or JSON ([https://datatracker.ietf.org/doc/html/rfc7517 RFC 7517]) format. The default value is empty.&lt;br /&gt;
* &#039;&#039;&#039;TokenLifetimeSeconds&#039;&#039;&#039; (integer): Token lifetime in seconds for the built-in OAuth identity provider. After access token created by built-in gets older than this lifetime, it becomes unusable and a new token has to be created. The default value is 3600.&lt;br /&gt;
* &#039;&#039;&#039;DisableExternalOAuthForwarding&#039;&#039;&#039; (boolean): Can be used to disable forwarding OAuth requests to any configured external OAuth authorization server or SAML identity provider. If set, a QPR ProcessAnalyzer&#039;s own login view functionality is always used when authorizing a user. The default value is false.&lt;br /&gt;
Example configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Issuer&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
  &amp;quot;AcceptedAudiences&amp;quot;: [&amp;quot;qpr-processanalyzer&amp;quot;],&lt;br /&gt;
  &amp;quot;SigningKey&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
  &amp;quot;TokenLifetime&amp;quot;: 3600&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Readonly Information ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;DatabaseVersion&amp;lt;/span&amp;gt;&lt;br /&gt;
||Database schema version. It will be updated automatically when the newer version of QPR ProcessAnalyzer Server connects to the database and performs migration for the database schema.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;InitializationScriptDatabaseVersion&amp;lt;/span&amp;gt;&lt;br /&gt;
||Database version that was when the database was initialized when the software was installed. Do not change this setting.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;MinimumDatabaseVersion&amp;lt;/span&amp;gt;&lt;br /&gt;
||Minimum allowed database version for QPR ProcessAnalyzer Server connecting to the database. This is a legacy setting and it should not be used.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=PA_Configuration_database_table&amp;diff=28074</id>
		<title>PA Configuration database table</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=PA_Configuration_database_table&amp;diff=28074"/>
		<updated>2026-04-09T12:20:59Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63184&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer database has a configuration table &#039;&#039;&#039;PA_Configuration&#039;&#039;&#039; containing settings listed in the tables below. You need &#039;&#039;&#039;SQL Server Management Studio&#039;&#039;&#039; to edit the settings in the configuration table. QPR ProcessAnalyzer Server needs to be restarted (e.g. IIS application pool recycled) for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
For boolean values, &#039;&#039;true&#039;&#039; and &#039;&#039;1&#039;&#039; are valid values for yes, and &#039;&#039;false&#039;&#039; and &#039;&#039;0&#039;&#039; are valid for no.&lt;br /&gt;
&lt;br /&gt;
== General Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||DefaultDataSource&lt;br /&gt;
||&lt;br /&gt;
||Datasource where datatables data is stored when datatables are created by a script when the datasource is not explicitly specified in the script. Options are &#039;&#039;&#039;Snowflake&#039;&#039;&#039; and &#039;&#039;&#039;SqlServer&#039;&#039;&#039;. Value &#039;&#039;snowflake&#039;&#039; can be used when the &#039;&#039;SnowflakeConnectionString&#039;&#039; setting is defined, and value &#039;&#039;sqlserver&#039;&#039; can be used when the setting &#039;&#039;SqlServerConnectionString&#039;&#039; is configured. The setting can be changed without affecting the existing datatables, as the setting only affect new datatables. When this setting is empty, datatables are created in the metadata database.&lt;br /&gt;
|-&lt;br /&gt;
||SnowflakeConnectionString&lt;br /&gt;
||&lt;br /&gt;
||ODBC connection string for the Snowflake account. This setting is needed to make analytics calculations in the Snowflake. More information how to configure the [[Snowflake_Connection_Configuration#Set_Snowflake_ODBC_connection|Snowflake connection string]]. The Snowflake ODBC driver also needs to be installed in the machine running the QPR ProcessAnalyzer Server. When this setting has been configured, users can create Snowflake stored datatables and models using Snowflake calculation.&lt;br /&gt;
&lt;br /&gt;
When running QPR ProcessAnalyzer in the Snowpark Container Services, leave the SnowflakeConnectionString empty because then the connection string is created automatically using the method provided by the Snowpark Container Services.&lt;br /&gt;
|-&lt;br /&gt;
||SqlServerConnectionString&lt;br /&gt;
||&lt;br /&gt;
||Connection string for the SQL Server database containing the datatables data. It&#039;s recommended to use a separate database, but it&#039;s also possible to connect to the same database as the configuration data. If this setting is not configured, local datatables cannot be created (SQL Server stored). Existing datatables located in the configuration datatabase still work even if this setting has not be configured. Note that the connection uses ADO.Net (not ODBC), so the connection string is similar to the configuration database ([[Server_settings_in_appsettings.json|appsettings.json]] file).&lt;br /&gt;
|-&lt;br /&gt;
||DefaultColorPalette&lt;br /&gt;
||&lt;br /&gt;
||Charts color palette used globally in the environment. Defined as a json array of strings encoded with RGB hex (with or without alpha). Note that when a color palette in a chart has been changed, the chart starts using a chart-specific color palette, and the global color palette doesn&#039;t affect those charts. &lt;br /&gt;
&lt;br /&gt;
Example: [&amp;quot;#1F77B4&amp;quot;, &amp;quot;#FF7F0E&amp;quot;, &amp;quot;#2CA02C&amp;quot;, &amp;quot;#D62728&amp;quot;, &amp;quot;#9467BD&amp;quot;, &amp;quot;#8C564B&amp;quot;, &amp;quot;#E377C2&amp;quot;, &amp;quot;#7F7F7F&amp;quot;, &amp;quot;#BCBD22&amp;quot;, &amp;quot;#17BECF&amp;quot;]&lt;br /&gt;
|-&lt;br /&gt;
||OpenAIAPIKey&lt;br /&gt;
||&lt;br /&gt;
||API key for the OpenAI API (https://platform.openai.com/docs/api-reference). It needs to be configured to use the [[AI_Assistant_for_QPR_ProcessAnalyzer|AI Assistant]] and [[Generic_Functions_in_QPR_ProcessAnalyzer#OpenAIChatCompletion|OpenAIChatCompletion]] function.&lt;br /&gt;
|-&lt;br /&gt;
||OpenAIDefaultModelName&lt;br /&gt;
||gpt-4o&lt;br /&gt;
||OpenAI large language model (LLM) to use for the [[AI_Assistant_for_QPR_ProcessAnalyzer|AI Assistant]] and [[Generic_Functions_in_QPR_ProcessAnalyzer#OpenAIChatCompletion|OpenAIChatCompletion]] function. If not defined, &#039;&#039;&#039;gpt-4o&#039;&#039;&#039; will be used. Note that only LLM&#039;s that support the function calling feature, are suitable for the AI Assistant. More information about OpenAI models: https://platform.openai.com/docs/models.&lt;br /&gt;
|-&lt;br /&gt;
||DefaultCortexAgentsModelName&lt;br /&gt;
||llama3.1-70b&lt;br /&gt;
||Specifies the default language model when using Snowflake Cortex Agents (https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-agents-rest-api). If not defined, &#039;&#039;&#039;llama3.1-70b&#039;&#039;&#039; is used.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;QueryTimeout&amp;quot;&amp;gt;QueryTimeout&amp;lt;/span&amp;gt;&lt;br /&gt;
||300&lt;br /&gt;
||Timeout (in seconds) for requests made to /api/expression/query and /api/expression endpoints. When the timeout is exceeded, the query is stopped and a timeout error is returned. Purpose of the timeout is to protect the system against potentially too long running or even never-ending queries which might otherwise jam the system.&lt;br /&gt;
|-&lt;br /&gt;
||SessionIdleTimeout&lt;br /&gt;
||3600&lt;br /&gt;
||Idle user session expiration timeout in seconds. User session expires if the session hasn&#039;t been used after this amount of time.&lt;br /&gt;
|-&lt;br /&gt;
||SessionMaximumDuration&lt;br /&gt;
||86400&lt;br /&gt;
||Maximum duration for a user session in seconds. Even if a session is used so that the SessionIdleTimeout is not reached, the session is expired after this amount of time.&lt;br /&gt;
|-&lt;br /&gt;
|DatabaseId&lt;br /&gt;
|&lt;br /&gt;
||Unique identifier for the QPR ProcessAnalyzer environment. Any characters between a-z, A-Z, 0-9 and _ (underscore) can be used in the DatabaseId. If the DatabaseId is missing or set to null, the system will generate a new GUID during startup and use it as the DatabaseId. The DatabaseId can also be an empty string. If using several QPR ProcessAnalyzer environments, make sure each use a different DatabaseId. The DatabaseId is used as part of the table names in Snowflake and SQL Server (in the datatables database). Thus if the DatabaseId is changed, all tables in Snowflake and SQL Server named with qprpa_dt_&amp;lt;DatabaseId&amp;gt;_&amp;lt;DatatableId&amp;gt; need to be renamed.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;CacheOnlyPrimaryKeysForFilters&amp;quot;&amp;gt;CacheOnlyPrimaryKeysForFilters&amp;lt;/span&amp;gt;&lt;br /&gt;
||false&lt;br /&gt;
||Defines whether to include all columns in the Snowflake event cache filter tables (&#039;&#039;false&#039;&#039;), or only the primary key columns (&#039;&#039;true&#039;&#039;). When &#039;&#039;false&#039;&#039;, cache table creation is slower, but the analysis calculation is faster because the original event table is not used anymore. When &#039;&#039;false&#039;&#039;, also the cache tables require more storage space in Snowflake.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Localization Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||DefaultUiLanguage&lt;br /&gt;
||en_US&lt;br /&gt;
||Language code for the UI language that new user accounts get by default. Thus, a created user account has this language until the user changes her/his language. Also the login page is translated using this language when QPR ProcessAnalyzer is used for the first time in that web browser (when user has changed the language, it&#039;s remembered by the browser). This setting must be one of the supported language codes (xx_XX):&lt;br /&gt;
* English: &#039;&#039;&#039;en_US&#039;&#039;&#039;&lt;br /&gt;
* Finnish: &#039;&#039;&#039;fi_FI&#039;&#039;&#039;&lt;br /&gt;
* French: &#039;&#039;&#039;fr_FR&#039;&#039;&#039;&lt;br /&gt;
* German: &#039;&#039;&#039;de_DE&#039;&#039;&#039;&lt;br /&gt;
* Polish: &#039;&#039;&#039;pl_PL&#039;&#039;&#039;&lt;br /&gt;
* Portuguese: &#039;&#039;&#039;pt_BR&#039;&#039;&#039;&lt;br /&gt;
* Spanish: &#039;&#039;&#039;es_ES&#039;&#039;&#039;&lt;br /&gt;
* Swedish: &#039;&#039;&#039;sv_SE&#039;&#039;&#039;&lt;br /&gt;
* Ukrainian: &#039;&#039;&#039;uk_UK&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||DefaultDateFormat&lt;br /&gt;
||MM/dd/yyyy&lt;br /&gt;
||Default date format that new user accounts get by default. The date format does not contain the time part (e.g. hours, minutes and seconds). Defined using the .Net date format (https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings).&lt;br /&gt;
|-&lt;br /&gt;
||DefaultFirstDayOfWeek&lt;br /&gt;
||0&lt;br /&gt;
||Default first day of the week that new user accounts get by default. &#039;&#039;&#039;0&#039;&#039;&#039; is Sunday and &#039;&#039;&#039;1&#039;&#039;&#039; is Monday. This information is used by the UI when showing e.g. calendars.&lt;br /&gt;
|-&lt;br /&gt;
||DefaultUse12HourClock&lt;br /&gt;
||false&lt;br /&gt;
||Defines whether the 12-hour clock is used by default (instead of the 24-hour clock) for the new user accounts when showing time information in the UI. Defined as &#039;&#039;&#039;true&#039;&#039;&#039; or &#039;&#039;&#039;false&#039;&#039;&#039;. More information about the 12-hour clock: https://en.wikipedia.org/wiki/12-hour_clock.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== ETL Scripts Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||AllowExternalDatasources&lt;br /&gt;
||true&lt;br /&gt;
||Can be used to disallow all connections to external datasources in the expression language and SQL scripts to improve security. Disallowed operations include ODBC, OLE DB, SQL Server (Ado.Net), SAP, Salesforce, and call web service. Note that this setting does not prevent the Snowflake processing. Regardless of this setting, QPR ScriptLauncher can be used to extract data from source systems.&lt;br /&gt;
|-&lt;br /&gt;
||SandboxDatabaseConnectionString&lt;br /&gt;
||&lt;br /&gt;
||Connection string to scripting sandbox database (ETL). If not defined, SQL-based ETL scripts cannot be run. Connection string for the scripting sandbox database is similar to the  [[Server_settings_in_appsettings.json|QPR ProcessAnalyzer database connection string]]. More information: [[Setting up Scripting Sandbox]].&lt;br /&gt;
|-&lt;br /&gt;
||AllowNonTemporaryETLTargetTable&lt;br /&gt;
||false&lt;br /&gt;
||Defined whether ETL scripts are allowed to create global temporary database tables (tables starting with ##). More information about temporary tables: https://docs.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql?view=sql-server-ver15#temporary-tables.&lt;br /&gt;
|-&lt;br /&gt;
||DatabaseBulkCopyTimeout&lt;br /&gt;
||600&lt;br /&gt;
||Timeout used for data import operations to datatables.&lt;br /&gt;
|-&lt;br /&gt;
|SandboxDatabaseBulkCopyTimeout&lt;br /&gt;
||600&lt;br /&gt;
||Timeout used for data import operations to sandbox tables in the SQL scripts.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;DatabaseBulkCopyBatchSize&amp;lt;/span&amp;gt;&lt;br /&gt;
||5000&lt;br /&gt;
||BulkCopyBatchSize given for QPR ProcessAnalyzer database SqlBulkCopy operations.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;SandboxDatabaseBulkCopyBatchSize&amp;lt;/span&amp;gt;&lt;br /&gt;
||5000&lt;br /&gt;
||BulkCopyBatchSize given for sandbox SqlBulkCopy operations.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== In-memory Calculation Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||NumberOfParallelModelReaders&lt;br /&gt;
||4&lt;br /&gt;
||Models and datatable contents can be loaded with multiple simultaneous connections to the database to speed up the loading. This setting determines how many parallel loaders/readers at maximum (loaders are loading at the same time). For smaller models there are less parallel loaders than the defined limit: If there are less than 100000 rows in the table, there is only one loader. If there are less than 200000 rows in the table, there are only two loaders, and so on. &lt;br /&gt;
&lt;br /&gt;
The more there are parallel loaders, the more processor load and network bandwidth is consumed, and other operations in QPR ProcessAnalyzer might slow down. Note also that the performance optimum is achieved with a certain number of parallel loaders which differs between environment. Thus to achieve the best performance, data loading should be tested with different number of parallel loaders. Increasing number of parallel loaders beyond the optimum decreases the performance.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
||StartupModelLoadingMaxParallelism&lt;br /&gt;
||2&lt;br /&gt;
||Maximum number of QPR ProcessAnalyzer models that are loaded into memory simultaneously by the [[Automatic_Model_Loading_on_Server_Startup|Automatic Loading on Server Startup]]. If there are more models to be loaded on the server startup than this setting, loading for the rest of the models is started one by one when previous model loadings are completed. If this setting is not defined, &#039;&#039;&#039;2&#039;&#039;&#039; is used as a default value.&lt;br /&gt;
&lt;br /&gt;
Loading more models at the same time will speed up the whole model loading process, but on the other hand, it causes more load on the system, which affects the system responsiveness for users. Model loading consists of (1) transferring data from the datasource to QPR ProcessAnalyzer and (2) loaded data preprocessing into a model. The former uses mainly network bandwidth (if datasource is in a different server) and the latter uses mainly processor capacity in the QPR ProcessAnalyzer server. &lt;br /&gt;
&lt;br /&gt;
This setting affects only the model loading during the server startup and it doesn&#039;t restrict models loadings initiated by users.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== SAML 2.0 Federated Authentication Settings ==&lt;br /&gt;
Note that the SAMLMetadataUrl and ServiceProviderLocation are mandatory for the federated authentication to work. Having both ExternalOAuthServerConfiguration and SAML authentication configured at the same time is not supported.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||SAMLMetadataUrl&lt;br /&gt;
||&lt;br /&gt;
Metadata URL of the identity provider (IdP). Check that the metadata url can actually be opened using a web browser and is publicly available. The metadata is an XML document starting with &#039;&#039;&#039;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&#039;&#039;&#039; followed by an &#039;&#039;&#039;EntityDescriptor&#039;&#039;&#039; tag. The metadata URL might look &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;https://your.federated.identity.provider.com/saml/metadata&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;. This setting is mandatory for the SAML authentication to work.&lt;br /&gt;
|-&lt;br /&gt;
||ServiceProviderLocation&lt;br /&gt;
||&lt;br /&gt;
Specifies the QPR ProcessAnalyzer server location (the root path which contains e.g. the &#039;&#039;ui&#039;&#039; folder). It&#039;s used by the url to redirect back to QPR ProcessAnalyzer after a successful authentication from the identity provider. The setting is defined in the following form: &#039;&#039;&#039;https://&amp;lt;hostname&amp;gt;/qprpa&#039;&#039;&#039;, for example &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;https://customer.onqpr.com/qprpa&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;. Note that the actual redirect back url is &#039;&#039;&#039;https://&amp;lt;hostname&amp;gt;/qprpa/api/Saml2/Acs&#039;&#039;&#039; (/api/Saml2/Acs is automatically included to the url). This setting is mandatory for the SAML authentication to work. Note that if this reply url is configured the identity provider, it must match with the ServiceProviderLocation setting.&lt;br /&gt;
|-&lt;br /&gt;
||SAMLUserIdAttribute&lt;br /&gt;
||&lt;br /&gt;
Name of the SAML attribute in the assertion that will be used as the user&#039;s login name. If this field is not defined, the &#039;&#039;&#039;saml:Assertion&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:Subject&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:NameID&#039;&#039;&#039; attribute in the assertion is used. If this setting is given, one of the &#039;&#039;&#039;saml:Assertion&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:AttributeStatement&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:Attribute&#039;&#039;&#039; elements in the assertion is used (the &#039;&#039;&#039;Name&#039;&#039;&#039; attribute in the &#039;&#039;&#039;saml:Attribute&#039;&#039;&#039; element is used for matching). Please note that the saml:NameID element is different than the usual SAML attributes that are defined by the saml:Attribute elements. For example, if an email address is used as a user id, the value of the setting could be for example &#039;&#039;&amp;lt;nowiki&amp;gt;http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress&amp;lt;/nowiki&amp;gt;&#039;&#039;.&lt;br /&gt;
|-&lt;br /&gt;
||SAMLGroupsAttribute&lt;br /&gt;
||Attribute name in SAML assertion that is mapped to user groups in QPR ProcessAnalyzer. The user group names are case sensitive. When a user logs in, the user is added to and removed from groups based on the information in the SAML assertion. If this setting is not configured, users are not added to or removed from groups automatically. Note that the user needs to login for the groups to be synchronized. If a group doesn&#039;t exist in QPR ProcessAnalyzer, that group is skipped.&lt;br /&gt;
&lt;br /&gt;
In the SAML assertion, attributes are in the saml:Assertion &amp;gt; saml:AttributeStatement &amp;gt; saml:Attribute elements (the Name attribute in the saml:Attribute element is used for matching).&lt;br /&gt;
|-&lt;br /&gt;
||SAMLEncryptionCertificate&lt;br /&gt;
||This setting defines a PFX formatted X.509 certificate (defined in RCF 1422) used to encrypt SAML assertions. The public key of the certificate is published in the service provider metadata, where the identity provider can read it and encrypt SAML assertions. QPR ProcessAnalyzer as the service provider uses the corresponding private key of the certificate to decrypt SAML assertions. The setting needs to be a PFX formatted certificate file that is base64 encoded and it doesn&#039;t contain the BEGIN CERTIFICATE etc. header or footer lines. This setting is needed only when using the SAML assertions encryption. Even though this setting is defined, the SAML assertions are not required to be encrypted. More information how to create the certificate file (https://stackoverflow.com/questions/16480846/x-509-private-public-key) and convert it to base64 (https://stackoverflow.com/questions/46959822/base-64-encoded-form-of-the-pfx-file).&lt;br /&gt;
|-&lt;br /&gt;
||SAMLSigningCertificate&lt;br /&gt;
||This setting defines a PFX formatted X.509 certificate (defined in RCF 1422) used to sign SAML authentication requests sent from QPR ProcessAnalyzer to the identity provider. The public key of the certificate is published in the service provider metadata, where the identity provider can read it, to verify the authenticity of the SAML requests. The setting needs to be a PFX formatted certificate file that is base64 encoded and it doesn&#039;t contain the BEGIN CERTIFICATE etc. header or footer lines. If this setting is not defined, the internal hard-coded signing certificate is used. More information how to create the certificate file (https://stackoverflow.com/questions/16480846/x-509-private-public-key) and convert it to base64 (https://stackoverflow.com/questions/46959822/base-64-encoded-form-of-the-pfx-file).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OAuth 2.0 Authentication Settings ==&lt;br /&gt;
Having both ExternalOAuthServerConfiguration and SAML authentication configured at the same time is not supported.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||ExternalOAuthServerConfiguration&lt;br /&gt;
||Used to configure OAuth 2.0 compatible OAuth server settings for server that is used to authenticate the user signing in to ProcessAnalyzer. If not set, external OAuth server will not be used for authentication. If set, contains a string representation of a JSON object that supports the following properties:&lt;br /&gt;
* &#039;&#039;&#039;Authority&#039;&#039;&#039; (string): OAuth authority URL for authentication. E.g., https://accounts.google.com/&lt;br /&gt;
* &#039;&#039;&#039;Audience&#039;&#039;&#039; (string): Mandatory. OAuth audience/client ID for validating OAuth tokens.&lt;br /&gt;
* &#039;&#039;&#039;AuthorizeUrlOverride&#039;&#039;&#039; (string): Override URL for the OAuth authorization endpoint. If empty or not defined, the default URL from the authority&#039;s discovery document is used.&lt;br /&gt;
* &#039;&#039;&#039;TokenUrlOverride&#039;&#039;&#039; (string): Override URL for the OAuth token endpoint. If empty or not defined, the default URL from the authority&#039;s discovery document is used.&lt;br /&gt;
* &#039;&#039;&#039;UserInfoUrlOverride&#039;&#039;&#039; (string): Override URL to fetch user information from the OAuth provider. If empty or not defined, the default URL from the authority&#039;s discovery document is used. Should not be used if OpendID Connect is to be used as access token validation is skipped.&lt;br /&gt;
* &#039;&#039;&#039;ClientSecret&#039;&#039;&#039; (string): OAuth client secret for confidential client authentication. If configured, this value is sent as the client_secret parameter when exchanging authorization codes for tokens.&lt;br /&gt;
* &#039;&#039;&#039;Issuer&#039;&#039;&#039; (string): OAuth issuer for validating OAuth tokens. If empty, the authority URL&#039;s issuer is used.&lt;br /&gt;
* &#039;&#039;&#039;UserNameClaim&#039;&#039;&#039; (string): Name of the claim whose value is to be used as the name of the authenticated user. The default value is &amp;quot;preferred_username&amp;quot;.&lt;br /&gt;
* &#039;&#039;&#039;UserGroupsClaim&#039;&#039;&#039; (string): Name of the claim whose value is to be used as the names of the user groups the authenticated user belongs to. When a user logs in, the user is added to and removed from groups based on the information in the UserGroupsClaim. If this setting is not configured, users are not added to or removed from groups automatically. Note that the user needs to login for the groups to be synchronized. If a group doesn&#039;t exist in QPR ProcessAnalyzer, that group is skipped. The default value is empty, i.e. groups are not synchronized.&amp;lt;br&amp;gt;&lt;br /&gt;
Example configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Authority&amp;quot;: &amp;quot;https://accounts.google.com/&amp;quot;,&lt;br /&gt;
  &amp;quot;AuthorizeUrlOverride&amp;quot;: &amp;quot;https://accounts.google.com/o/oauth2/v2/auth&amp;quot;,&lt;br /&gt;
  &amp;quot;TokenUrlOverride&amp;quot;: &amp;quot;https://oauth2.googleapis.com/token&amp;quot;,&lt;br /&gt;
  &amp;quot;UserInfoUrlOverride&amp;quot;: &amp;quot;https://www.googleapis.com/oauth2/v3/userinfo&amp;quot;,&lt;br /&gt;
  &amp;quot;Audience&amp;quot;: &amp;quot;...&amp;quot;,&lt;br /&gt;
  &amp;quot;ClientSecret&amp;quot;: &amp;quot;...&amp;quot;,&lt;br /&gt;
  &amp;quot;UserNameClaim&amp;quot;: &amp;quot;name&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== SMTP Server Settings ==&lt;br /&gt;
SMTP server settings are needed for QPR ProcessAnalyzer to send email messages. Email sending is used by the [[Email_Notifications|notifications]] and the [[Generic_Functions_in_QPR_ProcessAnalyzer#SendEmail|SendEmail]] function in the expression language.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||SmtpServer&lt;br /&gt;
||DNS name, host name or IP address of the SMTP server. Mandatory setting for the email sending to work.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpPort&lt;br /&gt;
||TCP port number of the SMTP server. If not defined, port 25 is used by default.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpAuthenticationUsername&lt;br /&gt;
||User name for authenticating to the SMTP server. If not defined, no authentication is used to connect to the SMTP server.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpFromAddress&lt;br /&gt;
||Email address where email messages sent by QPR ProcessAnalyzer appear to be coming from. This doesn&#039;t need to be a real email address, although the address used may affect email spam filters. The setting configured here is the default email address to use in following cases:&lt;br /&gt;
* &#039;&#039;From address&#039;&#039; is not set for the email notifications&lt;br /&gt;
* &#039;&#039;From&#039;&#039; parameter is not defined for the expression language &#039;&#039;SendEmail&#039;&#039; function&lt;br /&gt;
* &#039;&#039;EmailFrom&#039;&#039; parameter is not defined for the SQL Scripting SendEmail operation&lt;br /&gt;
|-&lt;br /&gt;
||SmtpAuthenticationPassword&lt;br /&gt;
||Password for authenticating to the SMTP server.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpEnableSSL&lt;br /&gt;
||Use value &#039;&#039;&#039;True&#039;&#039;&#039; or &#039;&#039;&#039;False&#039;&#039;&#039; depending whether TLS connection to the SMTP server is used or not. If not defined, &#039;&#039;False&#039;&#039; is the default value.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MCP Server Settings ==&lt;br /&gt;
MCP server settings are needed for QPR ProcessAnalyzer to act as an [[QPR_ProcessAnalyzer_as_MCP_Server|MCP server]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||McpServerConfiguration&lt;br /&gt;
||Used to configure the MCP server built-in to ProcessAnalyzer server. If not set, MCP server functionality is disabled and MCP clients can&#039;t access to this server using MCP. If set, contains a string representation of a JSON object that supports the following properties:&lt;br /&gt;
* &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; (string): If defined and not empty, defines the API key that can be used to connect to QPR ProcessAnalyzer MCP server without any other authentication. Default value is empty.&lt;br /&gt;
|-&lt;br /&gt;
||BuiltInOAuthServerConfiguration&lt;br /&gt;
||Used to configure OAuth 2.0 compatible OAuth server settings for OAuth server built-in to ProcessAnalyzer server. If not set, built-in OAuth server functionality is disabled and clients can&#039;t connect to this server using OAuth. If set, contains a string representation of a JSON object that supports the following properties: &lt;br /&gt;
* &#039;&#039;&#039;Issuer&#039;&#039;&#039; (string): OAuth issuer, which identifies a trusted authorization server that authenticates users and issues OAuth 2.0 access tokens and JSON Web Tokens (JWTs). If not defined or empty, default value is used, which is of format: &amp;lt;QPR ProcessAnalyzer server&#039;s base URL&amp;gt;/builtin-oauth. For example: https://example.com/builtin-oauth. The default value is empty.&lt;br /&gt;
* &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; (array of strings): Array of strings that define all the accepted audiences this QPR ProcessAnalyzer server is serving. When authorizing user using OAuth, these values are matched with the audience-parameter (a.k.a. client id) of the authorization. Only requests with a value that matches a value in this array are accepted. If null, audience-parameters are not validated at all. Instead, all authorization requests will pass the audience validation check. This also enables [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)]. The default value is an empty array.&lt;br /&gt;
* &#039;&#039;&#039;SigningKey&#039;&#039;&#039; (string): Signing key for the built-in OAuth identity provider. If empty, generates a non-deterministic key based on the physical system where QPR ProcessAnalyzer is running. NOTE: Once QPR ProcessAnalyzer server is restarted, these non-deterministic keys no longer work. If defined, string must contain the key either in PEM ([https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rsa.importfrompem?view=net-10.0 RFC 7468 PEM-encoded key]) or JSON ([https://datatracker.ietf.org/doc/html/rfc7517 RFC 7517]) format. The default value is empty.&lt;br /&gt;
* &#039;&#039;&#039;TokenLifetimeSeconds&#039;&#039;&#039; (integer): Token lifetime in seconds for the built-in OAuth identity provider. After access token created by built-in gets older than this lifetime, it becomes unusable and a new token has to be created. The default value is 3600.&lt;br /&gt;
* &#039;&#039;&#039;DisableExternalOAuthForwarding&#039;&#039;&#039; (boolean): Can be used to disable forwarding OAuth requests to any configured external OAuth authorization server or SAML identity provider. If set, a QPR ProcessAnalyzer&#039;s own login view functionality is always used when authorizing a user. The default value is false.&lt;br /&gt;
Example configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Issuer&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
  &amp;quot;AcceptedAudiences&amp;quot;: [&amp;quot;qpr-processanalyzer&amp;quot;],&lt;br /&gt;
  &amp;quot;SigningKey&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
  &amp;quot;TokenLifetime&amp;quot;: 3600&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Readonly Information ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;DatabaseVersion&amp;lt;/span&amp;gt;&lt;br /&gt;
||Database schema version. It will be updated automatically when the newer version of QPR ProcessAnalyzer Server connects to the database and performs migration for the database schema.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;InitializationScriptDatabaseVersion&amp;lt;/span&amp;gt;&lt;br /&gt;
||Database version that was when the database was initialized when the software was installed. Do not change this setting.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;MinimumDatabaseVersion&amp;lt;/span&amp;gt;&lt;br /&gt;
||Minimum allowed database version for QPR ProcessAnalyzer Server connecting to the database. This is a legacy setting and it should not be used.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=PA_Configuration_database_table&amp;diff=28070</id>
		<title>PA Configuration database table</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=PA_Configuration_database_table&amp;diff=28070"/>
		<updated>2026-04-09T11:55:53Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63184&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer database has a configuration table &#039;&#039;&#039;PA_Configuration&#039;&#039;&#039; containing settings listed in the tables below. You need &#039;&#039;&#039;SQL Server Management Studio&#039;&#039;&#039; to edit the settings in the configuration table. QPR ProcessAnalyzer Server needs to be restarted (e.g. IIS application pool recycled) for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
For boolean values, &#039;&#039;true&#039;&#039; and &#039;&#039;1&#039;&#039; are valid values for yes, and &#039;&#039;false&#039;&#039; and &#039;&#039;0&#039;&#039; are valid for no.&lt;br /&gt;
&lt;br /&gt;
== General Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||DefaultDataSource&lt;br /&gt;
||&lt;br /&gt;
||Datasource where datatables data is stored when datatables are created by a script when the datasource is not explicitly specified in the script. Options are &#039;&#039;&#039;Snowflake&#039;&#039;&#039; and &#039;&#039;&#039;SqlServer&#039;&#039;&#039;. Value &#039;&#039;snowflake&#039;&#039; can be used when the &#039;&#039;SnowflakeConnectionString&#039;&#039; setting is defined, and value &#039;&#039;sqlserver&#039;&#039; can be used when the setting &#039;&#039;SqlServerConnectionString&#039;&#039; is configured. The setting can be changed without affecting the existing datatables, as the setting only affect new datatables. When this setting is empty, datatables are created in the metadata database.&lt;br /&gt;
|-&lt;br /&gt;
||SnowflakeConnectionString&lt;br /&gt;
||&lt;br /&gt;
||ODBC connection string for the Snowflake account. This setting is needed to make analytics calculations in the Snowflake. More information how to configure the [[Snowflake_Connection_Configuration#Set_Snowflake_ODBC_connection|Snowflake connection string]]. The Snowflake ODBC driver also needs to be installed in the machine running the QPR ProcessAnalyzer Server. When this setting has been configured, users can create Snowflake stored datatables and models using Snowflake calculation.&lt;br /&gt;
&lt;br /&gt;
When running QPR ProcessAnalyzer in the Snowpark Container Services, leave the SnowflakeConnectionString empty because then the connection string is created automatically using the method provided by the Snowpark Container Services.&lt;br /&gt;
|-&lt;br /&gt;
||SqlServerConnectionString&lt;br /&gt;
||&lt;br /&gt;
||Connection string for the SQL Server database containing the datatables data. It&#039;s recommended to use a separate database, but it&#039;s also possible to connect to the same database as the configuration data. If this setting is not configured, local datatables cannot be created (SQL Server stored). Existing datatables located in the configuration datatabase still work even if this setting has not be configured. Note that the connection uses ADO.Net (not ODBC), so the connection string is similar to the configuration database ([[Server_settings_in_appsettings.json|appsettings.json]] file).&lt;br /&gt;
|-&lt;br /&gt;
||DefaultColorPalette&lt;br /&gt;
||&lt;br /&gt;
||Charts color palette used globally in the environment. Defined as a json array of strings encoded with RGB hex (with or without alpha). Note that when a color palette in a chart has been changed, the chart starts using a chart-specific color palette, and the global color palette doesn&#039;t affect those charts. &lt;br /&gt;
&lt;br /&gt;
Example: [&amp;quot;#1F77B4&amp;quot;, &amp;quot;#FF7F0E&amp;quot;, &amp;quot;#2CA02C&amp;quot;, &amp;quot;#D62728&amp;quot;, &amp;quot;#9467BD&amp;quot;, &amp;quot;#8C564B&amp;quot;, &amp;quot;#E377C2&amp;quot;, &amp;quot;#7F7F7F&amp;quot;, &amp;quot;#BCBD22&amp;quot;, &amp;quot;#17BECF&amp;quot;]&lt;br /&gt;
|-&lt;br /&gt;
||OpenAIAPIKey&lt;br /&gt;
||&lt;br /&gt;
||API key for the OpenAI API (https://platform.openai.com/docs/api-reference). It needs to be configured to use the [[AI_Assistant_for_QPR_ProcessAnalyzer|AI Assistant]] and [[Generic_Functions_in_QPR_ProcessAnalyzer#OpenAIChatCompletion|OpenAIChatCompletion]] function.&lt;br /&gt;
|-&lt;br /&gt;
||OpenAIDefaultModelName&lt;br /&gt;
||gpt-4o&lt;br /&gt;
||OpenAI large language model (LLM) to use for the [[AI_Assistant_for_QPR_ProcessAnalyzer|AI Assistant]] and [[Generic_Functions_in_QPR_ProcessAnalyzer#OpenAIChatCompletion|OpenAIChatCompletion]] function. If not defined, &#039;&#039;&#039;gpt-4o&#039;&#039;&#039; will be used. Note that only LLM&#039;s that support the function calling feature, are suitable for the AI Assistant. More information about OpenAI models: https://platform.openai.com/docs/models.&lt;br /&gt;
|-&lt;br /&gt;
||DefaultCortexAgentsModelName&lt;br /&gt;
||llama3.1-70b&lt;br /&gt;
||Specifies the default language model when using Snowflake Cortex Agents (https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-agents-rest-api). If not defined, &#039;&#039;&#039;llama3.1-70b&#039;&#039;&#039; is used.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;QueryTimeout&amp;quot;&amp;gt;QueryTimeout&amp;lt;/span&amp;gt;&lt;br /&gt;
||300&lt;br /&gt;
||Timeout (in seconds) for requests made to /api/expression/query and /api/expression endpoints. When the timeout is exceeded, the query is stopped and a timeout error is returned. Purpose of the timeout is to protect the system against potentially too long running or even never-ending queries which might otherwise jam the system.&lt;br /&gt;
|-&lt;br /&gt;
||SessionIdleTimeout&lt;br /&gt;
||3600&lt;br /&gt;
||Idle user session expiration timeout in seconds. User session expires if the session hasn&#039;t been used after this amount of time.&lt;br /&gt;
|-&lt;br /&gt;
||SessionMaximumDuration&lt;br /&gt;
||86400&lt;br /&gt;
||Maximum duration for a user session in seconds. Even if a session is used so that the SessionIdleTimeout is not reached, the session is expired after this amount of time.&lt;br /&gt;
|-&lt;br /&gt;
|DatabaseId&lt;br /&gt;
|&lt;br /&gt;
||Unique identifier for the QPR ProcessAnalyzer environment. Any characters between a-z, A-Z, 0-9 and _ (underscore) can be used in the DatabaseId. If the DatabaseId is missing or set to null, the system will generate a new GUID during startup and use it as the DatabaseId. The DatabaseId can also be an empty string. If using several QPR ProcessAnalyzer environments, make sure each use a different DatabaseId. The DatabaseId is used as part of the table names in Snowflake and SQL Server (in the datatables database). Thus if the DatabaseId is changed, all tables in Snowflake and SQL Server named with qprpa_dt_&amp;lt;DatabaseId&amp;gt;_&amp;lt;DatatableId&amp;gt; need to be renamed.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;CacheOnlyPrimaryKeysForFilters&amp;quot;&amp;gt;CacheOnlyPrimaryKeysForFilters&amp;lt;/span&amp;gt;&lt;br /&gt;
||false&lt;br /&gt;
||Defines whether to include all columns in the Snowflake event cache filter tables (&#039;&#039;false&#039;&#039;), or only the primary key columns (&#039;&#039;true&#039;&#039;). When &#039;&#039;false&#039;&#039;, cache table creation is slower, but the analysis calculation is faster because the original event table is not used anymore. When &#039;&#039;false&#039;&#039;, also the cache tables require more storage space in Snowflake.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Localization Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||DefaultUiLanguage&lt;br /&gt;
||en_US&lt;br /&gt;
||Language code for the UI language that new user accounts get by default. Thus, a created user account has this language until the user changes her/his language. Also the login page is translated using this language when QPR ProcessAnalyzer is used for the first time in that web browser (when user has changed the language, it&#039;s remembered by the browser). This setting must be one of the supported language codes (xx_XX):&lt;br /&gt;
* English: &#039;&#039;&#039;en_US&#039;&#039;&#039;&lt;br /&gt;
* Finnish: &#039;&#039;&#039;fi_FI&#039;&#039;&#039;&lt;br /&gt;
* French: &#039;&#039;&#039;fr_FR&#039;&#039;&#039;&lt;br /&gt;
* German: &#039;&#039;&#039;de_DE&#039;&#039;&#039;&lt;br /&gt;
* Polish: &#039;&#039;&#039;pl_PL&#039;&#039;&#039;&lt;br /&gt;
* Portuguese: &#039;&#039;&#039;pt_BR&#039;&#039;&#039;&lt;br /&gt;
* Spanish: &#039;&#039;&#039;es_ES&#039;&#039;&#039;&lt;br /&gt;
* Swedish: &#039;&#039;&#039;sv_SE&#039;&#039;&#039;&lt;br /&gt;
* Ukrainian: &#039;&#039;&#039;uk_UK&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||DefaultDateFormat&lt;br /&gt;
||MM/dd/yyyy&lt;br /&gt;
||Default date format that new user accounts get by default. The date format does not contain the time part (e.g. hours, minutes and seconds). Defined using the .Net date format (https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings).&lt;br /&gt;
|-&lt;br /&gt;
||DefaultFirstDayOfWeek&lt;br /&gt;
||0&lt;br /&gt;
||Default first day of the week that new user accounts get by default. &#039;&#039;&#039;0&#039;&#039;&#039; is Sunday and &#039;&#039;&#039;1&#039;&#039;&#039; is Monday. This information is used by the UI when showing e.g. calendars.&lt;br /&gt;
|-&lt;br /&gt;
||DefaultUse12HourClock&lt;br /&gt;
||false&lt;br /&gt;
||Defines whether the 12-hour clock is used by default (instead of the 24-hour clock) for the new user accounts when showing time information in the UI. Defined as &#039;&#039;&#039;true&#039;&#039;&#039; or &#039;&#039;&#039;false&#039;&#039;&#039;. More information about the 12-hour clock: https://en.wikipedia.org/wiki/12-hour_clock.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== ETL Scripts Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||AllowExternalDatasources&lt;br /&gt;
||true&lt;br /&gt;
||Can be used to disallow all connections to external datasources in the expression language and SQL scripts to improve security. Disallowed operations include ODBC, OLE DB, SQL Server (Ado.Net), SAP, Salesforce, and call web service. Note that this setting does not prevent the Snowflake processing. Regardless of this setting, QPR ScriptLauncher can be used to extract data from source systems.&lt;br /&gt;
|-&lt;br /&gt;
||SandboxDatabaseConnectionString&lt;br /&gt;
||&lt;br /&gt;
||Connection string to scripting sandbox database (ETL). If not defined, SQL-based ETL scripts cannot be run. Connection string for the scripting sandbox database is similar to the  [[Server_settings_in_appsettings.json|QPR ProcessAnalyzer database connection string]]. More information: [[Setting up Scripting Sandbox]].&lt;br /&gt;
|-&lt;br /&gt;
||AllowNonTemporaryETLTargetTable&lt;br /&gt;
||false&lt;br /&gt;
||Defined whether ETL scripts are allowed to create global temporary database tables (tables starting with ##). More information about temporary tables: https://docs.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql?view=sql-server-ver15#temporary-tables.&lt;br /&gt;
|-&lt;br /&gt;
||DatabaseBulkCopyTimeout&lt;br /&gt;
||600&lt;br /&gt;
||Timeout used for data import operations to datatables.&lt;br /&gt;
|-&lt;br /&gt;
|SandboxDatabaseBulkCopyTimeout&lt;br /&gt;
||600&lt;br /&gt;
||Timeout used for data import operations to sandbox tables in the SQL scripts.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;DatabaseBulkCopyBatchSize&amp;lt;/span&amp;gt;&lt;br /&gt;
||5000&lt;br /&gt;
||BulkCopyBatchSize given for QPR ProcessAnalyzer database SqlBulkCopy operations.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;SandboxDatabaseBulkCopyBatchSize&amp;lt;/span&amp;gt;&lt;br /&gt;
||5000&lt;br /&gt;
||BulkCopyBatchSize given for sandbox SqlBulkCopy operations.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== In-memory Calculation Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||NumberOfParallelModelReaders&lt;br /&gt;
||4&lt;br /&gt;
||Models and datatable contents can be loaded with multiple simultaneous connections to the database to speed up the loading. This setting determines how many parallel loaders/readers at maximum (loaders are loading at the same time). For smaller models there are less parallel loaders than the defined limit: If there are less than 100000 rows in the table, there is only one loader. If there are less than 200000 rows in the table, there are only two loaders, and so on. &lt;br /&gt;
&lt;br /&gt;
The more there are parallel loaders, the more processor load and network bandwidth is consumed, and other operations in QPR ProcessAnalyzer might slow down. Note also that the performance optimum is achieved with a certain number of parallel loaders which differs between environment. Thus to achieve the best performance, data loading should be tested with different number of parallel loaders. Increasing number of parallel loaders beyond the optimum decreases the performance.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
||StartupModelLoadingMaxParallelism&lt;br /&gt;
||2&lt;br /&gt;
||Maximum number of QPR ProcessAnalyzer models that are loaded into memory simultaneously by the [[Automatic_Model_Loading_on_Server_Startup|Automatic Loading on Server Startup]]. If there are more models to be loaded on the server startup than this setting, loading for the rest of the models is started one by one when previous model loadings are completed. If this setting is not defined, &#039;&#039;&#039;2&#039;&#039;&#039; is used as a default value.&lt;br /&gt;
&lt;br /&gt;
Loading more models at the same time will speed up the whole model loading process, but on the other hand, it causes more load on the system, which affects the system responsiveness for users. Model loading consists of (1) transferring data from the datasource to QPR ProcessAnalyzer and (2) loaded data preprocessing into a model. The former uses mainly network bandwidth (if datasource is in a different server) and the latter uses mainly processor capacity in the QPR ProcessAnalyzer server. &lt;br /&gt;
&lt;br /&gt;
This setting affects only the model loading during the server startup and it doesn&#039;t restrict models loadings initiated by users.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== SAML 2.0 Federated Authentication Settings ==&lt;br /&gt;
Note that the SAMLMetadataUrl and ServiceProviderLocation are mandatory for the federated authentication to work. Having both ExternalOAuthServerConfiguration and SAML authentication configured at the same time is not supported.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||SAMLMetadataUrl&lt;br /&gt;
||&lt;br /&gt;
Metadata URL of the identity provider (IdP). Check that the metadata url can actually be opened using a web browser and is publicly available. The metadata is an XML document starting with &#039;&#039;&#039;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&#039;&#039;&#039; followed by an &#039;&#039;&#039;EntityDescriptor&#039;&#039;&#039; tag. The metadata URL might look &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;https://your.federated.identity.provider.com/saml/metadata&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;. This setting is mandatory for the SAML authentication to work.&lt;br /&gt;
|-&lt;br /&gt;
||ServiceProviderLocation&lt;br /&gt;
||&lt;br /&gt;
Specifies the QPR ProcessAnalyzer server location (the root path which contains e.g. the &#039;&#039;ui&#039;&#039; folder). It&#039;s used by the url to redirect back to QPR ProcessAnalyzer after a successful authentication from the identity provider. The setting is defined in the following form: &#039;&#039;&#039;https://&amp;lt;hostname&amp;gt;/qprpa&#039;&#039;&#039;, for example &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;https://customer.onqpr.com/qprpa&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;. Note that the actual redirect back url is &#039;&#039;&#039;https://&amp;lt;hostname&amp;gt;/qprpa/api/Saml2/Acs&#039;&#039;&#039; (/api/Saml2/Acs is automatically included to the url). This setting is mandatory for the SAML authentication to work. Note that if this reply url is configured the identity provider, it must match with the ServiceProviderLocation setting.&lt;br /&gt;
|-&lt;br /&gt;
||SAMLUserIdAttribute&lt;br /&gt;
||&lt;br /&gt;
Name of the SAML attribute in the assertion that will be used as the user&#039;s login name. If this field is not defined, the &#039;&#039;&#039;saml:Assertion&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:Subject&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:NameID&#039;&#039;&#039; attribute in the assertion is used. If this setting is given, one of the &#039;&#039;&#039;saml:Assertion&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:AttributeStatement&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:Attribute&#039;&#039;&#039; elements in the assertion is used (the &#039;&#039;&#039;Name&#039;&#039;&#039; attribute in the &#039;&#039;&#039;saml:Attribute&#039;&#039;&#039; element is used for matching). Please note that the saml:NameID element is different than the usual SAML attributes that are defined by the saml:Attribute elements. For example, if an email address is used as a user id, the value of the setting could be for example &#039;&#039;&amp;lt;nowiki&amp;gt;http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress&amp;lt;/nowiki&amp;gt;&#039;&#039;.&lt;br /&gt;
|-&lt;br /&gt;
||SAMLGroupsAttribute&lt;br /&gt;
||Attribute name in SAML assertion that is mapped to user groups in QPR ProcessAnalyzer. The user group names are case sensitive. When a user logs in, the user is added to and removed from groups based on the information in the SAML assertion. If this setting is not configured, users are not added to or removed from groups automatically. Note that the user needs to login for the groups to be synchronized. If a group doesn&#039;t exist in QPR ProcessAnalyzer, that group is skipped.&lt;br /&gt;
&lt;br /&gt;
In the SAML assertion, attributes are in the saml:Assertion &amp;gt; saml:AttributeStatement &amp;gt; saml:Attribute elements (the Name attribute in the saml:Attribute element is used for matching).&lt;br /&gt;
|-&lt;br /&gt;
||SAMLEncryptionCertificate&lt;br /&gt;
||This setting defines a PFX formatted X.509 certificate (defined in RCF 1422) used to encrypt SAML assertions. The public key of the certificate is published in the service provider metadata, where the identity provider can read it and encrypt SAML assertions. QPR ProcessAnalyzer as the service provider uses the corresponding private key of the certificate to decrypt SAML assertions. The setting needs to be a PFX formatted certificate file that is base64 encoded and it doesn&#039;t contain the BEGIN CERTIFICATE etc. header or footer lines. This setting is needed only when using the SAML assertions encryption. Even though this setting is defined, the SAML assertions are not required to be encrypted. More information how to create the certificate file (https://stackoverflow.com/questions/16480846/x-509-private-public-key) and convert it to base64 (https://stackoverflow.com/questions/46959822/base-64-encoded-form-of-the-pfx-file).&lt;br /&gt;
|-&lt;br /&gt;
||SAMLSigningCertificate&lt;br /&gt;
||This setting defines a PFX formatted X.509 certificate (defined in RCF 1422) used to sign SAML authentication requests sent from QPR ProcessAnalyzer to the identity provider. The public key of the certificate is published in the service provider metadata, where the identity provider can read it, to verify the authenticity of the SAML requests. The setting needs to be a PFX formatted certificate file that is base64 encoded and it doesn&#039;t contain the BEGIN CERTIFICATE etc. header or footer lines. If this setting is not defined, the internal hard-coded signing certificate is used. More information how to create the certificate file (https://stackoverflow.com/questions/16480846/x-509-private-public-key) and convert it to base64 (https://stackoverflow.com/questions/46959822/base-64-encoded-form-of-the-pfx-file).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OAuth 2.0 Authentication Settings ==&lt;br /&gt;
Having both ExternalOAuthServerConfiguration and SAML authentication configured at the same time is not supported.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||ExternalOAuthServerConfiguration&lt;br /&gt;
||Used to configure OAuth 2.0 compatible OAuth server settings for server that is used to authenticate the user signing in to ProcessAnalyzer. If not set, external OAuth server will not be used for authentication. If set, contains a string representation of a JSON object that supports the following properties:&lt;br /&gt;
* &#039;&#039;&#039;Authority&#039;&#039;&#039; (string): OAuth authority URL for authentication. E.g., https://accounts.google.com/&lt;br /&gt;
* &#039;&#039;&#039;Audience&#039;&#039;&#039; (string): Mandatory. OAuth audience/client ID for validating OAuth tokens.&lt;br /&gt;
* &#039;&#039;&#039;AuthorizeUrlOverride&#039;&#039;&#039; (string): Override URL for the OAuth authorization endpoint. If empty or not defined, the default URL from the authority&#039;s discovery document is used.&lt;br /&gt;
* &#039;&#039;&#039;TokenUrlOverride&#039;&#039;&#039; (string): Override URL for the OAuth token endpoint. If empty or not defined, the default URL from the authority&#039;s discovery document is used.&lt;br /&gt;
* &#039;&#039;&#039;UserInfoUrlOverride&#039;&#039;&#039; (string): Override URL to fetch user information from the OAuth provider. If empty or not defined, the default URL from the authority&#039;s discovery document is used. Should not be used if OpendID Connect is to be used as access token validation is skipped.&lt;br /&gt;
* &#039;&#039;&#039;ClientSecret&#039;&#039;&#039; (string): OAuth client secret for confidential client authentication. If configured, this value is sent as the client_secret parameter when exchanging authorization codes for tokens.&lt;br /&gt;
* &#039;&#039;&#039;Issuer&#039;&#039;&#039; (string): OAuth issuer for validating OAuth tokens. If empty, the authority URL&#039;s issuer is used.&lt;br /&gt;
* &#039;&#039;&#039;UserNameClaim&#039;&#039;&#039; (string): Name of the claim whose value is to be used as the name of the authenticated user. The default value is &amp;quot;preferred_username&amp;quot;.&lt;br /&gt;
* &#039;&#039;&#039;UserGroupsClaim&#039;&#039;&#039; (string): Name of the claim whose value is to be used as the names of the user groups the authenticated user belongs to. When a user logs in, the user is added to and removed from groups based on the information in the UserGroupsClaim. If this setting is not configured, users are not added to or removed from groups automatically. Note that the user needs to login for the groups to be synchronized. If a group doesn&#039;t exist in QPR ProcessAnalyzer, that group is skipped. The default value is empty, i.e. groups are not synchronized.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== SMTP Server Settings ==&lt;br /&gt;
SMTP server settings are needed for QPR ProcessAnalyzer to send email messages. Email sending is used by the [[Email_Notifications|notifications]] and the [[Generic_Functions_in_QPR_ProcessAnalyzer#SendEmail|SendEmail]] function in the expression language.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||SmtpServer&lt;br /&gt;
||DNS name, host name or IP address of the SMTP server. Mandatory setting for the email sending to work.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpPort&lt;br /&gt;
||TCP port number of the SMTP server. If not defined, port 25 is used by default.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpAuthenticationUsername&lt;br /&gt;
||User name for authenticating to the SMTP server. If not defined, no authentication is used to connect to the SMTP server.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpFromAddress&lt;br /&gt;
||Email address where email messages sent by QPR ProcessAnalyzer appear to be coming from. This doesn&#039;t need to be a real email address, although the address used may affect email spam filters. The setting configured here is the default email address to use in following cases:&lt;br /&gt;
* &#039;&#039;From address&#039;&#039; is not set for the email notifications&lt;br /&gt;
* &#039;&#039;From&#039;&#039; parameter is not defined for the expression language &#039;&#039;SendEmail&#039;&#039; function&lt;br /&gt;
* &#039;&#039;EmailFrom&#039;&#039; parameter is not defined for the SQL Scripting SendEmail operation&lt;br /&gt;
|-&lt;br /&gt;
||SmtpAuthenticationPassword&lt;br /&gt;
||Password for authenticating to the SMTP server.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpEnableSSL&lt;br /&gt;
||Use value &#039;&#039;&#039;True&#039;&#039;&#039; or &#039;&#039;&#039;False&#039;&#039;&#039; depending whether TLS connection to the SMTP server is used or not. If not defined, &#039;&#039;False&#039;&#039; is the default value.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MCP Server Settings ==&lt;br /&gt;
MCP server settings are needed for QPR ProcessAnalyzer to act as an [[QPR_ProcessAnalyzer_as_MCP_Server|MCP server]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||McpServerConfiguration&lt;br /&gt;
||Used to configure the MCP server built-in to ProcessAnalyzer server. If not set, MCP server functionality is disabled and MCP clients can&#039;t access to this server using MCP. If set, contains a string representation of a JSON object that supports the following properties:&lt;br /&gt;
* McpApiKey: If defined and not empty, defines the API key that can be used to connect to QPR ProcessAnalyzer MCP server without any other authentication. Default value is empty.&lt;br /&gt;
|-&lt;br /&gt;
||BuiltInOAuthServerConfiguration&lt;br /&gt;
||Used to configure OAuth 2.0 compatible OAuth server settings for OAuth server built-in to ProcessAnalyzer server. If not set, built-in OAuth server functionality is disabled and clients can&#039;t connect to this server using OAuth. If set, contains a string representation of a JSON object that supports the following properties: &lt;br /&gt;
* &#039;&#039;&#039;Issuer&#039;&#039;&#039; (string): OAuth issuer, which identifies a trusted authorization server that authenticates users and issues OAuth 2.0 access tokens and JSON Web Tokens (JWTs). If not defined or empty, default value is used, which is of format: &amp;lt;QPR ProcessAnalyzer server&#039;s base URL&amp;gt;/builtin-oauth. For example: https://example.com/builtin-oauth. The default value is empty.&lt;br /&gt;
* &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; (array of strings): Array of strings that define all the accepted audiences this QPR ProcessAnalyzer server is serving. When authorizing user using OAuth, these values are matched with the audience-parameter (a.k.a. client id) of the authorization. Only requests with a value that matches a value in this array are accepted. If null, audience-parameters are not validated at all. Instead, all authorization requests will pass the audience validation check. This also enables [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)]. The default value is an empty array.&lt;br /&gt;
* &#039;&#039;&#039;SigningKey&#039;&#039;&#039; (string): Signing key for the built-in OAuth identity provider. If empty, generates a non-deterministic key based on the physical system where QPR ProcessAnalyzer is running. NOTE: Once QPR ProcessAnalyzer server is restarted, these non-deterministic keys no longer work. If defined, string must contain the key either in PEM ([https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rsa.importfrompem?view=net-10.0 RFC 7468 PEM-encoded key]) or JSON ([https://datatracker.ietf.org/doc/html/rfc7517 RFC 7517]) format. The default value is empty.&lt;br /&gt;
* &#039;&#039;&#039;TokenLifetimeSeconds&#039;&#039;&#039; (integer): Token lifetime in seconds for the built-in OAuth identity provider. After access token created by built-in gets older than this lifetime, it becomes unusable and a new token has to be created. The default value is 3600.&lt;br /&gt;
* &#039;&#039;&#039;DisableExternalOAuthForwarding&#039;&#039;&#039; (boolean): Can be used to disable forwarding OAuth requests to any configured external OAuth authorization server or SAML identity provider. If set, a QPR ProcessAnalyzer&#039;s own login view functionality is always used when authorizing a user. The default value is false.&lt;br /&gt;
Example configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Issuer&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
  &amp;quot;AcceptedAudiences&amp;quot;: [&amp;quot;qpr-processanalyzer&amp;quot;],&lt;br /&gt;
  &amp;quot;SigningKey&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
  &amp;quot;TokenLifetime&amp;quot;: 3600&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Readonly Information ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;DatabaseVersion&amp;lt;/span&amp;gt;&lt;br /&gt;
||Database schema version. It will be updated automatically when the newer version of QPR ProcessAnalyzer Server connects to the database and performs migration for the database schema.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;InitializationScriptDatabaseVersion&amp;lt;/span&amp;gt;&lt;br /&gt;
||Database version that was when the database was initialized when the software was installed. Do not change this setting.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;MinimumDatabaseVersion&amp;lt;/span&amp;gt;&lt;br /&gt;
||Minimum allowed database version for QPR ProcessAnalyzer Server connecting to the database. This is a legacy setting and it should not be used.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=Managing_Scripts&amp;diff=28069</id>
		<title>Managing Scripts</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=Managing_Scripts&amp;diff=28069"/>
		<updated>2026-04-09T11:49:51Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63184&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In QPR ProcessAnalyzer, scripts can be used for ETL tasks and to automate routines. Scripts are managed in the [[QPR_ProcessAnalyzer_Project_Workspace|Project Workspace]].&lt;br /&gt;
&lt;br /&gt;
=== Running vs. Calling Scripts ===&lt;br /&gt;
&#039;&#039;Running&#039;&#039; a script means starting executing a stored script, which can be done in the UI or using the ScriptLauncher. A script can also &#039;&#039;call&#039;&#039; other scripts during the run. The differences between the running and calling are:&lt;br /&gt;
* Script can run only once at a time, whereas there are no limitations on how many times a script can be called at the same time&lt;br /&gt;
* Script log is written to the running script. No script log is written to the called script.&lt;br /&gt;
* Script status shows whether the script is being run or not. The status does not change, when a script is called from other script.&lt;br /&gt;
&lt;br /&gt;
When a script is running, it&#039;s not possible to start another run of the same script, so the first run needs to end to start new. Scripts can call other scripts and a called scripts can run multiple times simultaneously. In the stack of called scripts, the script log is generated to the top level script. Also the top level script shows that it&#039;s running and the called scripts do not.&lt;br /&gt;
&lt;br /&gt;
=== Scripts List ===&lt;br /&gt;
When selecting a project and opening the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab, all scripts in the project can be seen. Scripts list shows following information:&lt;br /&gt;
* &#039;&#039;&#039;Name&#039;&#039;&#039;: Name of the script.&lt;br /&gt;
* &#039;&#039;&#039;Status&#039;&#039;&#039;: Status of the script, which is one of following: &#039;&#039;Ready&#039;&#039;, &#039;&#039;Running&#039;&#039; or &#039;&#039;Stopping&#039;&#039;. For more information about script statuses, see below.&lt;br /&gt;
* &#039;&#039;&#039;Last run duration&#039;&#039;&#039;: Duration of the last ended run of the script (the last run result can be any).&lt;br /&gt;
* &#039;&#039;&#039;Last run date&#039;&#039;&#039;: Date and time when the last run ended. If you need to know the last run start time, subtract the &#039;&#039;Last run duration&#039;&#039; from this time.&lt;br /&gt;
* &#039;&#039;&#039;Last run result&#039;&#039;&#039;: Result of the last run of the script. Either of following: &#039;&#039;Completed&#039;&#039;, &#039;&#039;Failed&#039;&#039; or &#039;&#039;Aborted&#039;&#039;. For more information about last run results, see below.&lt;br /&gt;
* &#039;&#039;&#039;Id&#039;&#039;&#039;: Script id that uniquely identifies the script in the system.&lt;br /&gt;
&lt;br /&gt;
Scrips are in either of following statuses:&lt;br /&gt;
* &#039;&#039;&#039;Ready&#039;&#039;&#039;: Script is currently not running, and can be started.&lt;br /&gt;
* &#039;&#039;&#039;Running&#039;&#039;&#039;: Script is currently running, and the script can be stopped. When a script is running, another run of the same script cannot be started.&lt;br /&gt;
* &#039;&#039;&#039;Stopping&#039;&#039;&#039;: Script is currently being stopped. When a script is in this status, the script cannot be started nor stopped, so you need to wait for the script to stop. There may be a delay in stopping a script, depending on the operation currently performed by the script.&lt;br /&gt;
&lt;br /&gt;
The last script run result can be either of the following:&lt;br /&gt;
* &#039;&#039;&#039;Completed&#039;&#039;&#039;: The last run ended successfully, i.e. without any errors or exceptions. Note that despite of the technically successful run, the script might still not work as intended.&lt;br /&gt;
* &#039;&#039;&#039;Failed&#039;&#039;&#039;: The last run ended to an error or exception. To see more information about the reason of the failure, see the [[#Viewing_Script_Log|last run log]].&lt;br /&gt;
* &#039;&#039;&#039;Aborted&#039;&#039;&#039;: The last run was stopped by a user, so the script did not run till the end.&lt;br /&gt;
&lt;br /&gt;
=== Script Properties ===&lt;br /&gt;
To open Script Properties, &#039;&#039;&#039;right-click&#039;&#039;&#039; the script on the Scripts tab in the Workspace and select &#039;&#039;&#039;Properties&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
The Script Properties lists the following information on the &#039;&#039;&#039;General&#039;&#039;&#039; tab:&lt;br /&gt;
* &#039;&#039;&#039;Script ID&#039;&#039;&#039;: A unique ID in the system.&lt;br /&gt;
* &#039;&#039;&#039;Language&#039;&#039;&#039;: The script&#039;s language, either &amp;quot;SQL&amp;quot; or &amp;quot;Expression&amp;quot;.&lt;br /&gt;
* &#039;&#039;&#039;Status&#039;&#039;&#039;: As above in Scripts List.&lt;br /&gt;
* &#039;&#039;&#039;Last run start&#039;&#039;&#039;: Date and time when the last run started.&lt;br /&gt;
* &#039;&#039;&#039;Last run end&#039;&#039;&#039;: As &amp;quot;Last run date&amp;quot; above in Scripts List.&lt;br /&gt;
* &#039;&#039;&#039;Last run duration&#039;&#039;&#039;: As above in Scripts List.&lt;br /&gt;
* &#039;&#039;&#039;Last run result&#039;&#039;&#039;: As above in Scripts List.&lt;br /&gt;
* &#039;&#039;&#039;Last modified&#039;&#039;&#039;: Date and time when the script was last modified.&lt;br /&gt;
* &#039;&#039;&#039;Last modified by&#039;&#039;&#039;: User who last modified the script.&lt;br /&gt;
* &#039;&#039;&#039;Created&#039;&#039;&#039;: Date and time when the script was created.&lt;br /&gt;
* &#039;&#039;&#039;Created by&#039;&#039;&#039;: User who created the script.&lt;br /&gt;
&lt;br /&gt;
The Script Properties has the following information on the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab:&lt;br /&gt;
* &#039;&#039;&#039;MCP tool&#039;&#039;&#039;: A checkbox to select whether the script can be used as an [[QPR_ProcessAnalyzer_as_MCP_Server|MCP]] tool.&lt;br /&gt;
&lt;br /&gt;
The Script Properties has the following information on the &#039;&#039;&#039;Description&#039;&#039;&#039; tab:&lt;br /&gt;
* A textbox to edit the description of the script.&lt;br /&gt;
&lt;br /&gt;
=== Editing Script ===&lt;br /&gt;
Open the scripts editor as follows:&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and in the right-click context menu select &#039;&#039;&#039;Edit&#039;&#039;&#039;. Alternatively, you can hover the script and click the &#039;&#039;Edit&#039;&#039; button in the end of the row.&lt;br /&gt;
&lt;br /&gt;
The script editor can show multiple scripts in the tabs, allowing to easily switch between the scrips. The editor remembers all scripts that have been opened during the session.&lt;br /&gt;
&lt;br /&gt;
In the script editor, you can:&lt;br /&gt;
* Run the script by clicking the &#039;&#039;&#039;Run&#039;&#039;&#039; button.&lt;br /&gt;
* Stop a running script by clicking the &#039;&#039;&#039;Stop&#039;&#039;&#039; button.&lt;br /&gt;
* Save a script having unsaved changes by clicking the &#039;&#039;&#039;Save&#039;&#039;&#039; button.&lt;br /&gt;
* To run a script having unsaved changes, click the &#039;&#039;&#039;Save and Run&#039;&#039;&#039; button. Note that the script needs to be saved to run it.&lt;br /&gt;
* To go back to the list of scripts, click the &#039;&#039;&#039;Go back&#039;&#039;&#039; button. If there are unsaved changes in any of the opened scripts, you need to either save or cancel the changes.&lt;br /&gt;
* To close a script, click the &#039;&#039;Close&#039;&#039; button for the tab showing the script. If there are unsaved changes, you need to either save or cancel changes.&lt;br /&gt;
&lt;br /&gt;
=== Starting Script ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and in the right-click context menu select &#039;&#039;&#039;Run&#039;&#039;&#039;. Alternatively, you can hover the script and click the &#039;&#039;Run&#039;&#039; button in the end of the row.&lt;br /&gt;
&lt;br /&gt;
Note that when running a script in the UI, the script must not contain commands where &#039;&#039;ExecuteInClientSide&#039;&#039; is enabled, because that is only supported when running scripts using [[QPR_ProcessAnalyzer_ScriptLauncher|QPR ScriptLauncher]].&lt;br /&gt;
&lt;br /&gt;
=== Stopping Script ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and from the right-click context menu select &#039;&#039;&#039;Stop&#039;&#039;&#039;. Alternatively, you can hover the script and click the &#039;&#039;Stop&#039;&#039; button in the end of the row.&lt;br /&gt;
&lt;br /&gt;
Note that it may take a while for a script to actually stop, depending on what kind of operation the script is executing when it&#039;s stopped.&lt;br /&gt;
&lt;br /&gt;
=== Viewing Script Log ===&lt;br /&gt;
It&#039;s possible to see the script log of the last run, and monitor the currently running script progress. Logs for older runs are not available in the UI, nut they are stored by the system.&lt;br /&gt;
&lt;br /&gt;
To see the logs:&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and in the right-click context menu select either &#039;&#039;&#039;View last run log&#039;&#039;&#039; or &#039;&#039;&#039;View current run log&#039;&#039;&#039;. (The script needs to be running to open the current run log.)&lt;br /&gt;
# If keeping the current run log open, the latest log entries are updated automatically every two seconds.&lt;br /&gt;
&lt;br /&gt;
More information about [[QPR_ProcessAnalyzer_Logs#Script_Log|Script Log]].&lt;br /&gt;
&lt;br /&gt;
=== Creating Script ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where you want to create a script.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Click the &#039;&#039;&#039;New&#039;&#039;&#039; button and click &#039;&#039;&#039;Script&#039;&#039;&#039;. Define a name for the script and the scripting &#039;&#039;&#039;Language&#039;&#039;&#039; (either &#039;&#039;&#039;Expression&#039;&#039;&#039; or &#039;&#039;&#039;SQL&#039;&#039;&#039;), and then click &#039;&#039;&#039;Create&#039;&#039;&#039;. Note that script names must be unique within a project.&lt;br /&gt;
&lt;br /&gt;
Note that the scripting language cannot be changed after the script has been created, so a new script needs to be created to change the language.&lt;br /&gt;
&lt;br /&gt;
Note that each script in the same project needs to have a unique name.&lt;br /&gt;
&lt;br /&gt;
=== Deleting Script ===&lt;br /&gt;
# Select the project where the script(s) to be deleted are located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select one or several scripts to be deleted.&lt;br /&gt;
# Click the &#039;&#039;&#039;Delete&#039;&#039;&#039; button and click &#039;&#039;&#039;Delete&#039;&#039;&#039; to the confirmation message.&lt;br /&gt;
&lt;br /&gt;
Note that if the script is being run, it cannot be deleted.&lt;br /&gt;
&lt;br /&gt;
=== Renaming Script ===&lt;br /&gt;
# Select the project where the script to be renamed is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script to be renamed.&lt;br /&gt;
# Click the &#039;&#039;&#039;Rename&#039;&#039;&#039; button.&lt;br /&gt;
# Change the script name in the opening dialog and click &#039;&#039;&#039;OK&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Moving Script ===&lt;br /&gt;
Scripts can be moved by dragging them with the left mouse button from the right side list to the target project in the left side hierarchy. Alternatively, you can first select the scripts, then from the right-click context menu select &#039;&#039;&#039;Move to&#039;&#039;&#039; and finally select the target project.&lt;br /&gt;
&lt;br /&gt;
=== Duplicating Script ===&lt;br /&gt;
# Select the project where the script to be duplicated is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script to be duplicated.&lt;br /&gt;
# Click the &#039;&#039;&#039;Duplicate&#039;&#039;&#039; button. A duplicate of the script is created.&lt;br /&gt;
&lt;br /&gt;
=== Viewing Script Run Results ===&lt;br /&gt;
Script runs can be [[Managing_Scripts#Running_Script|started]] and [[Managing_Scripts#Stopping_Script|stopped]] in the UI. Note that when running scripts using the UI, return values or results of the script cannot be viewed. If you want to use scripts that return data, there are following options:&lt;br /&gt;
* Script can write data to the script log&lt;br /&gt;
* Script can write data to a datatable&lt;br /&gt;
* Script can be called from a dashboard and use the dashboard to present the returned data (see more below).&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=Managing_Scripts&amp;diff=28068</id>
		<title>Managing Scripts</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=Managing_Scripts&amp;diff=28068"/>
		<updated>2026-04-09T11:49:29Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63184&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In QPR ProcessAnalyzer, scripts can be used for ETL tasks and to automate routines. Scripts are managed in the [[QPR_ProcessAnalyzer_Project_Workspace|Project Workspace]].&lt;br /&gt;
&lt;br /&gt;
=== Running vs. Calling Scripts ===&lt;br /&gt;
&#039;&#039;Running&#039;&#039; a script means starting executing a stored script, which can be done in the UI or using the ScriptLauncher. A script can also &#039;&#039;call&#039;&#039; other scripts during the run. The differences between the running and calling are:&lt;br /&gt;
* Script can run only once at a time, whereas there are no limitations on how many times a script can be called at the same time&lt;br /&gt;
* Script log is written to the running script. No script log is written to the called script.&lt;br /&gt;
* Script status shows whether the script is being run or not. The status does not change, when a script is called from other script.&lt;br /&gt;
&lt;br /&gt;
When a script is running, it&#039;s not possible to start another run of the same script, so the first run needs to end to start new. Scripts can call other scripts and a called scripts can run multiple times simultaneously. In the stack of called scripts, the script log is generated to the top level script. Also the top level script shows that it&#039;s running and the called scripts do not.&lt;br /&gt;
&lt;br /&gt;
=== Scripts List ===&lt;br /&gt;
When selecting a project and opening the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab, all scripts in the project can be seen. Scripts list shows following information:&lt;br /&gt;
* &#039;&#039;&#039;Name&#039;&#039;&#039;: Name of the script.&lt;br /&gt;
* &#039;&#039;&#039;Status&#039;&#039;&#039;: Status of the script, which is one of following: &#039;&#039;Ready&#039;&#039;, &#039;&#039;Running&#039;&#039; or &#039;&#039;Stopping&#039;&#039;. For more information about script statuses, see below.&lt;br /&gt;
* &#039;&#039;&#039;Last run duration&#039;&#039;&#039;: Duration of the last ended run of the script (the last run result can be any).&lt;br /&gt;
* &#039;&#039;&#039;Last run date&#039;&#039;&#039;: Date and time when the last run ended. If you need to know the last run start time, subtract the &#039;&#039;Last run duration&#039;&#039; from this time.&lt;br /&gt;
* &#039;&#039;&#039;Last run result&#039;&#039;&#039;: Result of the last run of the script. Either of following: &#039;&#039;Completed&#039;&#039;, &#039;&#039;Failed&#039;&#039; or &#039;&#039;Aborted&#039;&#039;. For more information about last run results, see below.&lt;br /&gt;
* &#039;&#039;&#039;Id&#039;&#039;&#039;: Script id that uniquely identifies the script in the system.&lt;br /&gt;
&lt;br /&gt;
Scrips are in either of following statuses:&lt;br /&gt;
* &#039;&#039;&#039;Ready&#039;&#039;&#039;: Script is currently not running, and can be started.&lt;br /&gt;
* &#039;&#039;&#039;Running&#039;&#039;&#039;: Script is currently running, and the script can be stopped. When a script is running, another run of the same script cannot be started.&lt;br /&gt;
* &#039;&#039;&#039;Stopping&#039;&#039;&#039;: Script is currently being stopped. When a script is in this status, the script cannot be started nor stopped, so you need to wait for the script to stop. There may be a delay in stopping a script, depending on the operation currently performed by the script.&lt;br /&gt;
&lt;br /&gt;
The last script run result can be either of the following:&lt;br /&gt;
* &#039;&#039;&#039;Completed&#039;&#039;&#039;: The last run ended successfully, i.e. without any errors or exceptions. Note that despite of the technically successful run, the script might still not work as intended.&lt;br /&gt;
* &#039;&#039;&#039;Failed&#039;&#039;&#039;: The last run ended to an error or exception. To see more information about the reason of the failure, see the [[#Viewing_Script_Log|last run log]].&lt;br /&gt;
* &#039;&#039;&#039;Aborted&#039;&#039;&#039;: The last run was stopped by a user, so the script did not run till the end.&lt;br /&gt;
&lt;br /&gt;
=== Script Properties ===&lt;br /&gt;
To open Script Properties, &#039;&#039;&#039;right-click&#039;&#039;&#039; the script on the Scripts tab in the Workspace and select &#039;&#039;&#039;Properties&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
The Script Properties lists the following information on the &#039;&#039;&#039;General&#039;&#039; tab:&lt;br /&gt;
* &#039;&#039;&#039;Script ID&#039;&#039;&#039;: A unique ID in the system.&lt;br /&gt;
* &#039;&#039;&#039;Language&#039;&#039;&#039;: The script&#039;s language, either &amp;quot;SQL&amp;quot; or &amp;quot;Expression&amp;quot;.&lt;br /&gt;
* &#039;&#039;&#039;Status&#039;&#039;&#039;: As above in Scripts List.&lt;br /&gt;
* &#039;&#039;&#039;Last run start&#039;&#039;&#039;: Date and time when the last run started.&lt;br /&gt;
* &#039;&#039;&#039;Last run end&#039;&#039;&#039;: As &amp;quot;Last run date&amp;quot; above in Scripts List.&lt;br /&gt;
* &#039;&#039;&#039;Last run duration&#039;&#039;&#039;: As above in Scripts List.&lt;br /&gt;
* &#039;&#039;&#039;Last run result&#039;&#039;&#039;: As above in Scripts List.&lt;br /&gt;
* &#039;&#039;&#039;Last modified&#039;&#039;&#039;: Date and time when the script was last modified.&lt;br /&gt;
* &#039;&#039;&#039;Last modified by&#039;&#039;&#039;: User who last modified the script.&lt;br /&gt;
* &#039;&#039;&#039;Created&#039;&#039;&#039;: Date and time when the script was created.&lt;br /&gt;
* &#039;&#039;&#039;Created by&#039;&#039;&#039;: User who created the script.&lt;br /&gt;
&lt;br /&gt;
The Script Properties has the following information on the &#039;&#039;&#039;MCP&#039;&#039; tab:&lt;br /&gt;
* &#039;&#039;&#039;MCP tool&#039;&#039;&#039;: A checkbox to select whether the script can be used as an [[QPR_ProcessAnalyzer_as_MCP_Server|MCP]] tool.&lt;br /&gt;
&lt;br /&gt;
The Script Properties has the following information on the &#039;&#039;&#039;Description&#039;&#039; tab:&lt;br /&gt;
* A textbox to edit the description of the script.&lt;br /&gt;
&lt;br /&gt;
=== Editing Script ===&lt;br /&gt;
Open the scripts editor as follows:&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and in the right-click context menu select &#039;&#039;&#039;Edit&#039;&#039;&#039;. Alternatively, you can hover the script and click the &#039;&#039;Edit&#039;&#039; button in the end of the row.&lt;br /&gt;
&lt;br /&gt;
The script editor can show multiple scripts in the tabs, allowing to easily switch between the scrips. The editor remembers all scripts that have been opened during the session.&lt;br /&gt;
&lt;br /&gt;
In the script editor, you can:&lt;br /&gt;
* Run the script by clicking the &#039;&#039;&#039;Run&#039;&#039;&#039; button.&lt;br /&gt;
* Stop a running script by clicking the &#039;&#039;&#039;Stop&#039;&#039;&#039; button.&lt;br /&gt;
* Save a script having unsaved changes by clicking the &#039;&#039;&#039;Save&#039;&#039;&#039; button.&lt;br /&gt;
* To run a script having unsaved changes, click the &#039;&#039;&#039;Save and Run&#039;&#039;&#039; button. Note that the script needs to be saved to run it.&lt;br /&gt;
* To go back to the list of scripts, click the &#039;&#039;&#039;Go back&#039;&#039;&#039; button. If there are unsaved changes in any of the opened scripts, you need to either save or cancel the changes.&lt;br /&gt;
* To close a script, click the &#039;&#039;Close&#039;&#039; button for the tab showing the script. If there are unsaved changes, you need to either save or cancel changes.&lt;br /&gt;
&lt;br /&gt;
=== Starting Script ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and in the right-click context menu select &#039;&#039;&#039;Run&#039;&#039;&#039;. Alternatively, you can hover the script and click the &#039;&#039;Run&#039;&#039; button in the end of the row.&lt;br /&gt;
&lt;br /&gt;
Note that when running a script in the UI, the script must not contain commands where &#039;&#039;ExecuteInClientSide&#039;&#039; is enabled, because that is only supported when running scripts using [[QPR_ProcessAnalyzer_ScriptLauncher|QPR ScriptLauncher]].&lt;br /&gt;
&lt;br /&gt;
=== Stopping Script ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and from the right-click context menu select &#039;&#039;&#039;Stop&#039;&#039;&#039;. Alternatively, you can hover the script and click the &#039;&#039;Stop&#039;&#039; button in the end of the row.&lt;br /&gt;
&lt;br /&gt;
Note that it may take a while for a script to actually stop, depending on what kind of operation the script is executing when it&#039;s stopped.&lt;br /&gt;
&lt;br /&gt;
=== Viewing Script Log ===&lt;br /&gt;
It&#039;s possible to see the script log of the last run, and monitor the currently running script progress. Logs for older runs are not available in the UI, nut they are stored by the system.&lt;br /&gt;
&lt;br /&gt;
To see the logs:&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and in the right-click context menu select either &#039;&#039;&#039;View last run log&#039;&#039;&#039; or &#039;&#039;&#039;View current run log&#039;&#039;&#039;. (The script needs to be running to open the current run log.)&lt;br /&gt;
# If keeping the current run log open, the latest log entries are updated automatically every two seconds.&lt;br /&gt;
&lt;br /&gt;
More information about [[QPR_ProcessAnalyzer_Logs#Script_Log|Script Log]].&lt;br /&gt;
&lt;br /&gt;
=== Creating Script ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where you want to create a script.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Click the &#039;&#039;&#039;New&#039;&#039;&#039; button and click &#039;&#039;&#039;Script&#039;&#039;&#039;. Define a name for the script and the scripting &#039;&#039;&#039;Language&#039;&#039;&#039; (either &#039;&#039;&#039;Expression&#039;&#039;&#039; or &#039;&#039;&#039;SQL&#039;&#039;&#039;), and then click &#039;&#039;&#039;Create&#039;&#039;&#039;. Note that script names must be unique within a project.&lt;br /&gt;
&lt;br /&gt;
Note that the scripting language cannot be changed after the script has been created, so a new script needs to be created to change the language.&lt;br /&gt;
&lt;br /&gt;
Note that each script in the same project needs to have a unique name.&lt;br /&gt;
&lt;br /&gt;
=== Deleting Script ===&lt;br /&gt;
# Select the project where the script(s) to be deleted are located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select one or several scripts to be deleted.&lt;br /&gt;
# Click the &#039;&#039;&#039;Delete&#039;&#039;&#039; button and click &#039;&#039;&#039;Delete&#039;&#039;&#039; to the confirmation message.&lt;br /&gt;
&lt;br /&gt;
Note that if the script is being run, it cannot be deleted.&lt;br /&gt;
&lt;br /&gt;
=== Renaming Script ===&lt;br /&gt;
# Select the project where the script to be renamed is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script to be renamed.&lt;br /&gt;
# Click the &#039;&#039;&#039;Rename&#039;&#039;&#039; button.&lt;br /&gt;
# Change the script name in the opening dialog and click &#039;&#039;&#039;OK&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Moving Script ===&lt;br /&gt;
Scripts can be moved by dragging them with the left mouse button from the right side list to the target project in the left side hierarchy. Alternatively, you can first select the scripts, then from the right-click context menu select &#039;&#039;&#039;Move to&#039;&#039;&#039; and finally select the target project.&lt;br /&gt;
&lt;br /&gt;
=== Duplicating Script ===&lt;br /&gt;
# Select the project where the script to be duplicated is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script to be duplicated.&lt;br /&gt;
# Click the &#039;&#039;&#039;Duplicate&#039;&#039;&#039; button. A duplicate of the script is created.&lt;br /&gt;
&lt;br /&gt;
=== Viewing Script Run Results ===&lt;br /&gt;
Script runs can be [[Managing_Scripts#Running_Script|started]] and [[Managing_Scripts#Stopping_Script|stopped]] in the UI. Note that when running scripts using the UI, return values or results of the script cannot be viewed. If you want to use scripts that return data, there are following options:&lt;br /&gt;
* Script can write data to the script log&lt;br /&gt;
* Script can write data to a datatable&lt;br /&gt;
* Script can be called from a dashboard and use the dashboard to present the returned data (see more below).&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28067</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28067"/>
		<updated>2026-04-09T11:18:46Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63184&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API Keys. It&#039;s also possible to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table as &#039;&#039;&#039;null&#039;&#039;&#039;.&lt;br /&gt;
* Set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_Configuration database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
When QPR ProcessAnalyzer is hosted in IIS, some clients (for example [https://modelcontextprotocol.io/docs/tools/inspector MCP Inspector]) may expect [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint:&amp;lt;br&amp;gt;&lt;br /&gt;
/.well-known/openid-configuration&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To make this work, add an IIS rewrite rule and a CORS header at the IIS root-level &#039;&#039;&#039;web.config&#039;&#039;&#039;. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&amp;lt;br&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
=== Oauth 2.0 and API Key Authentication ===&lt;br /&gt;
This method combines both per-user authentication and static API key authentication. To use both OAuth 2.0 and API key Authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client using API key authentication must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
* Set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_Configuration database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
== Implementing MCP Tools with Scripts ==&lt;br /&gt;
Any QPR ProcessAnalyzer script can be turned into an MCP tool. This is controlled in the [[Managing_Scripts#Script_Properties|Script Properties]].&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab and select the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;Description&#039;&#039;&#039; tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table.&lt;br /&gt;
** &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_Configuration database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)].&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
Connect to Server: In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., http://your-pa-server/qprpa/api/mcp) and select streamable-http as the transport type.&amp;lt;br&amp;gt;&lt;br /&gt;
Authenticate: Configure the necessary authentication header (e.g., X-Mcp-Api-Key).&amp;lt;br&amp;gt;&lt;br /&gt;
List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool named GetCurrentTime, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
    &amp;quot;params&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;GetCurrentTime&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
        &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
            &amp;quot;progressToken&amp;quot;: 2&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;jsonrpc&amp;quot;: &amp;quot;2.0&amp;quot;,&lt;br /&gt;
    &amp;quot;id&amp;quot;: 2&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category: QPR ProcessAnalyzer]]&lt;br /&gt;
[[Category: MCP]]&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28066</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28066"/>
		<updated>2026-04-09T11:17:54Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63184&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API Keys. It&#039;s also possible to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table as &#039;&#039;&#039;null&#039;&#039;&#039;.&lt;br /&gt;
* Set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_Configuration database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
When QPR ProcessAnalyzer is hosted in IIS, some clients (for example [https://modelcontextprotocol.io/docs/tools/inspector MCP Inspector]) may expect [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint:&amp;lt;br&amp;gt;&lt;br /&gt;
/.well-known/openid-configuration&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To make this work, add an IIS rewrite rule and a CORS header at the IIS root-level &#039;&#039;&#039;web.config&#039;&#039;&#039;. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&amp;lt;br&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
=== Oauth 2.0 and API Key Authentication ===&lt;br /&gt;
This method combines both per-user authentication and static API key authentication. To use both OAuth 2.0 and API key Authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client using API key authentication must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
* Set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_Configuration database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
== Implementing MCP Tools with Scripts ==&lt;br /&gt;
Any QPR ProcessAnalyzer script can be turned into an MCP tool. This is controlled in the [[Managing_Scripts#Script_Properties|Script Properties]].&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab and select the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;Description&#039;&#039;&#039; tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table.&lt;br /&gt;
** &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_Configuration database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)].&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
Connect to Server: In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., http://your-pa-server/qprpa/api/mcp) and select streamable-http as the transport type.&amp;lt;br&amp;gt;&lt;br /&gt;
Authenticate: Configure the necessary authentication header (e.g., X-Mcp-Api-Key).&amp;lt;br&amp;gt;&lt;br /&gt;
List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool named GetCurrentTime, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
    &amp;quot;params&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;GetCurrentTime&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
        &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
            &amp;quot;progressToken&amp;quot;: 2&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;jsonrpc&amp;quot;: &amp;quot;2.0&amp;quot;,&lt;br /&gt;
    &amp;quot;id&amp;quot;: 2&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28065</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28065"/>
		<updated>2026-04-09T11:17:20Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63184&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API Keys. It&#039;s also possible to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table as &#039;&#039;&#039;null&#039;&#039;&#039;.&lt;br /&gt;
* Set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_Configuration database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
When QPR ProcessAnalyzer is hosted in IIS, some clients (for example [https://modelcontextprotocol.io/docs/tools/inspector MCP Inspector]) may expect [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint:&amp;lt;br&amp;gt;&lt;br /&gt;
/.well-known/openid-configuration&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To make this work, add an IIS rewrite rule and a CORS header at the IIS root-level &#039;&#039;&#039;web.config&#039;&#039;&#039;. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&amp;lt;br&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
=== Oauth 2.0 and API Key Authentication ===&lt;br /&gt;
This method combines both per-user authentication and static API key authentication. To use both OAuth 2.0 and API key Authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client using API key authentication must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
* Set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_Configuration database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
== Implementing MCP Tools with Scripts ==&lt;br /&gt;
Any QPR ProcessAnalyzer script can be turned into an MCP tool. This is controlled in the [[Managing_Scripts#Script_Properties|Script Properties]].&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab and select the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;Description&#039;&#039;&#039; tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table.&lt;br /&gt;
** &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_Configuration database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)].&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
Connect to Server: In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., http://your-pa-server/qprpa/api/mcp) and select streamable-http as the transport type.&lt;br /&gt;
Authenticate: Configure the necessary authentication header (e.g., X-Mcp-Api-Key).&lt;br /&gt;
List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool named GetCurrentTime, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
    &amp;quot;params&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;GetCurrentTime&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
        &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
            &amp;quot;progressToken&amp;quot;: 2&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;jsonrpc&amp;quot;: &amp;quot;2.0&amp;quot;,&lt;br /&gt;
    &amp;quot;id&amp;quot;: 2&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28064</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28064"/>
		<updated>2026-04-09T11:15:10Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63184&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API Keys. It&#039;s also possible to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table as &#039;&#039;&#039;null&#039;&#039;&#039;.&lt;br /&gt;
* Set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_Configuration database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
When QPR ProcessAnalyzer is hosted in IIS, some clients (for example [https://modelcontextprotocol.io/docs/tools/inspector MCP Inspector]) may expect [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint:&amp;lt;br&amp;gt;&lt;br /&gt;
/.well-known/openid-configuration&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To make this work, add an IIS rewrite rule and a CORS header at the IIS root-level &#039;&#039;&#039;web.config&#039;&#039;&#039;. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&amp;lt;br&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
=== Oauth 2.0 and API Key Authentication ===&lt;br /&gt;
This method combines both per-user authentication and static API key authentication. To use both OAuth 2.0 and API key Authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client using API key authentication must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
* Set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_Configuration database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
== Implementing MCP Tools with Scripts ==&lt;br /&gt;
Any QPR ProcessAnalyzer script can be turned into an MCP tool. This is controlled in the [[Managing_Scripts#Script_Properties|Script Properties]].&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;MCP&#039;&#039;&#039; tab and select the &#039;&#039;&#039;MCP tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the &#039;&#039;&#039;Description&#039;&#039;&#039; tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table.&lt;br /&gt;
** &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_Configuration database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)].&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
Connect to Server: In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., http://localhost:5000/qprpa/api/mcp) and select streamable-http as the transport type.&lt;br /&gt;
Authenticate: Configure the necessary authentication header (e.g., X-Mcp-Api-Key).&lt;br /&gt;
List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool named GetCurrentTime, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
    &amp;quot;params&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;GetCurrentTime&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
        &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
            &amp;quot;progressToken&amp;quot;: 2&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;jsonrpc&amp;quot;: &amp;quot;2.0&amp;quot;,&lt;br /&gt;
    &amp;quot;id&amp;quot;: 2&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28063</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28063"/>
		<updated>2026-04-09T11:14:14Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63184&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API Keys. It&#039;s also possible to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table as &#039;&#039;&#039;null&#039;&#039;&#039;.&lt;br /&gt;
* Set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_Configuration database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
When QPR ProcessAnalyzer is hosted in IIS, some clients (for example [https://modelcontextprotocol.io/docs/tools/inspector MCP Inspector]) may expect [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint:&amp;lt;br&amp;gt;&lt;br /&gt;
/.well-known/openid-configuration&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To make this work, add an IIS rewrite rule and a CORS header at the IIS root-level &#039;&#039;&#039;web.config&#039;&#039;&#039;. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&amp;lt;br&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
=== Oauth 2.0 and API Key Authentication ===&lt;br /&gt;
This method combines both per-user authentication and static API key authentication. To use both OAuth 2.0 and API key Authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client using API key authentication must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
* Set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_Configuration database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
== Implementing MCP Tools with Scripts ==&lt;br /&gt;
Any QPR ProcessAnalyzer script can be turned into an MCP tool. This is controlled in the [[Managing_Scripts#Script_Properties|Script Properties]].&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the MCP tab and select the &#039;&#039;&#039;MCP Tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the Description tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table.&lt;br /&gt;
** &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_Configuration database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)].&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
Connect to Server: In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., http://localhost:5000/qprpa/api/mcp) and select streamable-http as the transport type.&lt;br /&gt;
Authenticate: Configure the necessary authentication header (e.g., X-Mcp-Api-Key).&lt;br /&gt;
List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool named GetCurrentTime, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
    &amp;quot;params&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;GetCurrentTime&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
        &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
            &amp;quot;progressToken&amp;quot;: 2&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;jsonrpc&amp;quot;: &amp;quot;2.0&amp;quot;,&lt;br /&gt;
    &amp;quot;id&amp;quot;: 2&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28062</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28062"/>
		<updated>2026-04-09T11:13:36Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63184&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API Keys. It&#039;s also possible to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table as &#039;&#039;&#039;null&#039;&#039;&#039;.&lt;br /&gt;
* Set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_Configuration database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
When QPR ProcessAnalyzer is hosted in IIS, some clients (for example [https://modelcontextprotocol.io/docs/tools/inspector MCP Inspector]) may expect [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint:&amp;lt;br&amp;gt;&lt;br /&gt;
/.well-known/openid-configuration&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To make this work, add an IIS rewrite rule and a CORS header at the IIS root-level &#039;&#039;&#039;web.config&#039;&#039;&#039;. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&amp;lt;br&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039; header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
=== Oauth 2.0 and API Key Authentication ===&lt;br /&gt;
This method combines both per-user authentication and static API key authentication. To use both OAuth 2.0 and API key Authentication:&lt;br /&gt;
* Set the McpApiKey value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client using API key authentication must then include this key in the X-Mcp-Api-Key header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
* Set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_Configuration database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
== Implementing MCP Tools with Scripts ==&lt;br /&gt;
Any QPR ProcessAnalyzer script can be turned into an MCP tool. This is controlled in the [[Managing_Scripts#Script_Properties|Script Properties]].&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the MCP tab and select the &#039;&#039;&#039;MCP Tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the Description tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table.&lt;br /&gt;
** &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_Configuration database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)].&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
Connect to Server: In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., http://localhost:5000/qprpa/api/mcp) and select streamable-http as the transport type.&lt;br /&gt;
Authenticate: Configure the necessary authentication header (e.g., X-Mcp-Api-Key).&lt;br /&gt;
List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool named GetCurrentTime, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
    &amp;quot;params&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;GetCurrentTime&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
        &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
            &amp;quot;progressToken&amp;quot;: 2&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;jsonrpc&amp;quot;: &amp;quot;2.0&amp;quot;,&lt;br /&gt;
    &amp;quot;id&amp;quot;: 2&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28061</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28061"/>
		<updated>2026-04-09T11:12:13Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63184&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API Keys. It&#039;s also possible to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table as &#039;&#039;&#039;null&#039;&#039;&#039;.&lt;br /&gt;
* Set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_Configuration database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
When QPR ProcessAnalyzer is hosted in IIS, some clients (for example [https://modelcontextprotocol.io/docs/tools/inspector MCP Inspector]) may expect [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint:&amp;lt;br&amp;gt;&lt;br /&gt;
/.well-known/openid-configuration&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To make this work, add an IIS rewrite rule and a CORS header at the IIS root-level &#039;&#039;&#039;web.config&#039;&#039;&#039;. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&amp;lt;br&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the McpApiKey value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the X-Mcp-Api-Key header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
=== Oauth 2.0 and API Key Authentication ===&lt;br /&gt;
This method combines both per-user authentication and static API key authentication. To use both OAuth 2.0 and API key Authentication:&lt;br /&gt;
* Set the McpApiKey value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client using API key authentication must then include this key in the X-Mcp-Api-Key header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
* Set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_Configuration database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
== Implementing MCP Tools with Scripts ==&lt;br /&gt;
Any QPR ProcessAnalyzer script can be turned into an MCP tool. This is controlled in the [[Managing_Scripts#Script_Properties|Script Properties]].&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the MCP tab and select the &#039;&#039;&#039;MCP Tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the Description tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table.&lt;br /&gt;
** &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_Configuration database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)].&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
Connect to Server: In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., http://localhost:5000/qprpa/api/mcp) and select streamable-http as the transport type.&lt;br /&gt;
Authenticate: Configure the necessary authentication header (e.g., X-Mcp-Api-Key).&lt;br /&gt;
List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool named GetCurrentTime, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
    &amp;quot;params&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;GetCurrentTime&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
        &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
            &amp;quot;progressToken&amp;quot;: 2&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;jsonrpc&amp;quot;: &amp;quot;2.0&amp;quot;,&lt;br /&gt;
    &amp;quot;id&amp;quot;: 2&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28060</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28060"/>
		<updated>2026-04-09T11:11:11Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63184&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API Keys. It&#039;s also possible to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table as &#039;&#039;&#039;null&#039;&#039;&#039;.&lt;br /&gt;
* Set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_Configuration database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
When QPR ProcessAnalyzer is hosted in IIS, some clients (for example [https://modelcontextprotocol.io/docs/tools/inspector MCP Inspector]) may expect [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint:&amp;lt;br&amp;gt;&lt;br /&gt;
/.well-known/openid-configuration&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To make this work, add an IIS rewrite rule and a CORS header at the IIS root-level web.config. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&amp;lt;br&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the McpApiKey value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the X-Mcp-Api-Key header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
=== Oauth 2.0 and API Key Authentication ===&lt;br /&gt;
This method combines both per-user authentication and static API key authentication. To use both OAuth 2.0 and API key Authentication:&lt;br /&gt;
* Set the McpApiKey value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client using API key authentication must then include this key in the X-Mcp-Api-Key header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
* Set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_Configuration database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
== Implementing MCP Tools with Scripts ==&lt;br /&gt;
Any QPR ProcessAnalyzer script can be turned into an MCP tool. This is controlled in the [[Managing_Scripts#Script_Properties|Script Properties]].&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the MCP tab and select the &#039;&#039;&#039;MCP Tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the Description tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table.&lt;br /&gt;
** &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_Configuration database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)].&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
Connect to Server: In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., http://localhost:5000/qprpa/api/mcp) and select streamable-http as the transport type.&lt;br /&gt;
Authenticate: Configure the necessary authentication header (e.g., X-Mcp-Api-Key).&lt;br /&gt;
List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool named GetCurrentTime, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
    &amp;quot;params&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;GetCurrentTime&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
        &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
            &amp;quot;progressToken&amp;quot;: 2&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;jsonrpc&amp;quot;: &amp;quot;2.0&amp;quot;,&lt;br /&gt;
    &amp;quot;id&amp;quot;: 2&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28059</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28059"/>
		<updated>2026-04-09T11:10:23Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63184&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
The supported methods to authenticate MCP clients are OAuth 2.0 or API Keys. It&#039;s also possible to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table as null.&lt;br /&gt;
* Set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_Configuration database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
When QPR ProcessAnalyzer is hosted in IIS, some clients (for example [https://modelcontextprotocol.io/docs/tools/inspector MCP Inspector]) may expect [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint:&amp;lt;br&amp;gt;&lt;br /&gt;
/.well-known/openid-configuration&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To make this work, add an IIS rewrite rule and a CORS header at the IIS root-level web.config. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&amp;lt;br&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the McpApiKey value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the X-Mcp-Api-Key header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
=== Oauth 2.0 and API Key Authentication ===&lt;br /&gt;
This method combines both per-user authentication and static API key authentication. To use both OAuth 2.0 and API key Authentication:&lt;br /&gt;
* Set the McpApiKey value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client using API key authentication must then include this key in the X-Mcp-Api-Key header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
* Set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_Configuration database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
== Implementing MCP Tools with Scripts ==&lt;br /&gt;
Any QPR ProcessAnalyzer script can be turned into an MCP tool. This is controlled in the [[Managing_Scripts#Script_Properties|Script Properties]].&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the MCP tab and select the &#039;&#039;&#039;MCP Tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the Description tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table.&lt;br /&gt;
** &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_Configuration database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)].&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
Connect to Server: In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., http://localhost:5000/qprpa/api/mcp) and select streamable-http as the transport type.&lt;br /&gt;
Authenticate: Configure the necessary authentication header (e.g., X-Mcp-Api-Key).&lt;br /&gt;
List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool named GetCurrentTime, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
    &amp;quot;params&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;GetCurrentTime&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
        &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
            &amp;quot;progressToken&amp;quot;: 2&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;jsonrpc&amp;quot;: &amp;quot;2.0&amp;quot;,&lt;br /&gt;
    &amp;quot;id&amp;quot;: 2&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28058</id>
		<title>QPR ProcessAnalyzer as MCP Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=QPR_ProcessAnalyzer_as_MCP_Server&amp;diff=28058"/>
		<updated>2026-04-09T11:08:26Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63184&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer can act as a Model Context Protocol (MCP) server, allowing external tools and applications to interact with its analysis capabilities through script-based tools.&lt;br /&gt;
&lt;br /&gt;
== Overview of MCP Server Functionality ==&lt;br /&gt;
The Model Context Protocol (MCP) is a standard for communication between modeling tools. By acting as an MCP server, QPR ProcessAnalyzer exposes its functionalities, which are implemented as [[Managing_Scripts|scripts]], to any MCP-compliant client. This enables a wide range of integrations and automation possibilities.&lt;br /&gt;
&lt;br /&gt;
Key features:&lt;br /&gt;
* Script-based Tools: Any QPR ProcessAnalyzer script can be exposed as an MCP tool.&lt;br /&gt;
* Flexible Authentication: Supports both API Key and OAuth 2.0 for secure access.&lt;br /&gt;
* Standardized Communication: Uses the MCP standard for interoperability with clients like MCP Inspector and Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
== Configuring the MCP Server ==&lt;br /&gt;
To enable and configure the MCP server functionality in QPR ProcessAnalyzer, a system administrator needs to adjust the McpServerConfiguration setting in the [[PA_Configuration_database_table|PA Configuration Database Table]].&lt;br /&gt;
&lt;br /&gt;
== Authentication Methods ==&lt;br /&gt;
You can choose between two methods to authenticate MCP clients: OAuth 2.0 or API Keys. It&#039;s also possible to use both.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2.0 Authentication ===&lt;br /&gt;
This method provides per-user authentication, allowing each MCP request to be authenticated against a specific QPR ProcessAnalyzer user. This is the recommended authentication method for MCP. To use OAuth 2.0 Authentication:&lt;br /&gt;
* Set the &#039;&#039;&#039;McpApiKey&#039;&#039;&#039; value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table as null.&lt;br /&gt;
* Set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_Configuration database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
==== Setting up IIS to support OpenId Connect Discovery ====&lt;br /&gt;
When QPR ProcessAnalyzer is hosted in IIS, some clients (for example [https://modelcontextprotocol.io/docs/tools/inspector MCP Inspector]) may expect [https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig OpenID Connect discovery metadata] to be available from the standard endpoint:&amp;lt;br&amp;gt;&lt;br /&gt;
/.well-known/openid-configuration&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To make this work, add an IIS rewrite rule and a CORS header at the IIS root-level web.config. Adding rewrite rules to IIS requires [https://www.iis.net/downloads/microsoft/url-rewrite URL Rewrite] to be installed on the system.&lt;br /&gt;
&lt;br /&gt;
: 1. Open the root-level IIS web.config.&lt;br /&gt;
: 2. Add the following configuration under &amp;lt;system.webServer&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;configuration&amp;gt;&lt;br /&gt;
  &amp;lt;system.webServer&amp;gt;&lt;br /&gt;
    &amp;lt;rewrite&amp;gt;&lt;br /&gt;
      &amp;lt;rules&amp;gt;&lt;br /&gt;
        &amp;lt;rule name=&amp;quot;Redirect OIDC Discovery - openid-configuration&amp;quot; stopProcessing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;match url=&amp;quot;^\.well-known/openid-configuration$&amp;quot; /&amp;gt;&lt;br /&gt;
          &amp;lt;action type=&amp;quot;Redirect&amp;quot;&lt;br /&gt;
                  url=&amp;quot;&amp;lt;QPR ProcessAnalyzer Path&amp;gt;/builtin-oauth/.well-known/openid-configuration&amp;quot;&lt;br /&gt;
                  redirectType=&amp;quot;Permanent&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/rule&amp;gt;&lt;br /&gt;
      &amp;lt;/rules&amp;gt;&lt;br /&gt;
    &amp;lt;/rewrite&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
    &amp;lt;httpProtocol&amp;gt;&lt;br /&gt;
      &amp;lt;customHeaders&amp;gt;&lt;br /&gt;
        &amp;lt;add name=&amp;quot;Access-Control-Allow-Origin&amp;quot; value=&amp;quot;&amp;lt;Allowed CORS origins&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/customHeaders&amp;gt;&lt;br /&gt;
    &amp;lt;/httpProtocol&amp;gt;&lt;br /&gt;
  &amp;lt;/system.webServer&amp;gt;&lt;br /&gt;
&amp;lt;/configuration&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
: 3. Replace placeholders:&lt;br /&gt;
:* &amp;lt;QPR ProcessAnalyzer Path&amp;gt;: IIS virtual path to the installed QPR ProcessAnalyzer application, for example qprpa.&lt;br /&gt;
:* &amp;lt;Allowed CORS origins&amp;gt;: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS CORS origin] origin(s) allowed to call discovery. Use specific origin(s) in production.&lt;br /&gt;
&lt;br /&gt;
You may also need to add the URL of the client accessing the MCP server to the CorsOrigins setting in the server&#039;s [[Server_settings_in_appsettings.json|appsettings.json]].&lt;br /&gt;
&lt;br /&gt;
After configuration, the following URL should return OpenID provider metadata:&amp;lt;br&amp;gt;&lt;br /&gt;
https://&amp;lt;your-host&amp;gt;/.well-known/openid-configuration&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
If the endpoint does not work, verify that the rewrite rule is in the IIS root-level web.config and that the target path resolves to .../builtin-oauth/.well-known/openid-configuration.&lt;br /&gt;
&lt;br /&gt;
=== API Key Authentication ===&lt;br /&gt;
This method uses a static, pre-shared key for all MCP requests. To use API key authentication:&lt;br /&gt;
* Set the McpApiKey value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client must then include this key in the X-Mcp-Api-Key header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
&lt;br /&gt;
=== Oauth 2.0 and API Key Authentication ===&lt;br /&gt;
This method combines both per-user authentication and static API key authentication. To use both OAuth 2.0 and API key Authentication:&lt;br /&gt;
* Set the McpApiKey value in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table. The MCP client using API key authentication must then include this key in the X-Mcp-Api-Key header of each request.&lt;br /&gt;
* Create a user named &amp;quot;MCP Client&amp;quot; in QPR ProcessAnalyzer. All the MCP server operations are performed in the context of &amp;quot;MCP Client&amp;quot; user, i.e. the user can&#039;t see or modify anything the &amp;quot;MCP Client&amp;quot; user can&#039;t see or modify in any other way.&lt;br /&gt;
* Set the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] value in the PA_Configuration database table with at least an &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; value other than the default.&lt;br /&gt;
&lt;br /&gt;
== Implementing MCP Tools with Scripts ==&lt;br /&gt;
Any QPR ProcessAnalyzer script can be turned into an MCP tool. This is controlled in the [[Managing_Scripts#Script_Properties|Script Properties]].&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To enable a script as an MCP Tool:&lt;br /&gt;
# Log in to QPR ProcessAnalyzer as a System Administrator.&lt;br /&gt;
# For the script to be used as an MCP tool, give it a name. This name is then used as the MCP tool name. It is important to ensure that every script intended for MCP use has a non-empty, valid name, as clients may fail to discover tools with invalid names.&lt;br /&gt;
# Open the properties of the script.&lt;br /&gt;
# Switch to the MCP tab and select the &#039;&#039;&#039;MCP Tool&#039;&#039;&#039; checkbox.&lt;br /&gt;
# Switch to the Description tab and provide a description. The description is added to the context of the client.&lt;br /&gt;
&lt;br /&gt;
== Connecting as an MCP Client ==&lt;br /&gt;
MCP clients can connect to the QPR ProcessAnalyzer server to discover and execute the available tools. The endpoint and connection details are:&lt;br /&gt;
* &#039;&#039;&#039;URL&#039;&#039;&#039;: The primary MCP endpoint is located at /api/mcp relative to the QPR ProcessAnalyzer server URL (e.g., https://your-pa-server.com/qprpa/api/mcp).&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039;: http.&lt;br /&gt;
* &#039;&#039;&#039;Headers&#039;&#039;&#039;: Clients must include the following headers in their requests:&lt;br /&gt;
** &#039;&#039;&#039;X-Mcp-Api-Key&#039;&#039;&#039;: Used when authenticating with API key. The API key that is defined in the [[PA_Configuration_database_table#MCP_Server_Settings|McpServerConfiguration]] setting in the PA_Configuration database table.&lt;br /&gt;
** &#039;&#039;&#039;Client ID&#039;&#039;&#039;: Used when authenticating with OAuth 2.0. If the AcceptedAudiences value in the [[PA_Configuration_database_table#MCP_Server_Settings|BuiltInOAuthServerConfiguration]] setting in the PA_Configuration database table is something else than null, the client ID has to match it. If the AcceptedAudiences value is null, the client ID must be created with [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)].&lt;br /&gt;
&lt;br /&gt;
=== Example: Using MCP Inspector ===&lt;br /&gt;
MCP Inspector is a standard client that can be used to test the connection and interact with the MCP tools.&lt;br /&gt;
&lt;br /&gt;
Connect to Server: In MCP Inspector, provide the server&#039;s MCP endpoint URL (e.g., http://localhost:5000/qprpa/api/mcp) and select streamable-http as the transport type.&lt;br /&gt;
Authenticate: Configure the necessary authentication header (e.g., X-Mcp-Api-Key).&lt;br /&gt;
List and Call Tools: Once connected, you can list the available tools and call them. For example, to call a tool named GetCurrentTime, the client would send a JSON-RPC request like the one below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;method&amp;quot;: &amp;quot;tools/call&amp;quot;,&lt;br /&gt;
    &amp;quot;params&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;GetCurrentTime&amp;quot;,&lt;br /&gt;
        &amp;quot;arguments&amp;quot;: {},&lt;br /&gt;
        &amp;quot;_meta&amp;quot;: {&lt;br /&gt;
            &amp;quot;progressToken&amp;quot;: 2&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;jsonrpc&amp;quot;: &amp;quot;2.0&amp;quot;,&lt;br /&gt;
    &amp;quot;id&amp;quot;: 2&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=Managing_Scripts&amp;diff=28057</id>
		<title>Managing Scripts</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=Managing_Scripts&amp;diff=28057"/>
		<updated>2026-04-09T09:55:38Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63184&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In QPR ProcessAnalyzer, scripts can be used for ETL tasks and to automate routines. Scripts are managed in the [[QPR_ProcessAnalyzer_Project_Workspace|Project Workspace]].&lt;br /&gt;
&lt;br /&gt;
=== Running vs. Calling Scripts ===&lt;br /&gt;
&#039;&#039;Running&#039;&#039; a script means starting executing a stored script, which can be done in the UI or using the ScriptLauncher. A script can also &#039;&#039;call&#039;&#039; other scripts during the run. The differences between the running and calling are:&lt;br /&gt;
* Script can run only once at a time, whereas there are no limitations on how many times a script can be called at the same time&lt;br /&gt;
* Script log is written to the running script. No script log is written to the called script.&lt;br /&gt;
* Script status shows whether the script is being run or not. The status does not change, when a script is called from other script.&lt;br /&gt;
&lt;br /&gt;
When a script is running, it&#039;s not possible to start another run of the same script, so the first run needs to end to start new. Scripts can call other scripts and a called scripts can run multiple times simultaneously. In the stack of called scripts, the script log is generated to the top level script. Also the top level script shows that it&#039;s running and the called scripts do not.&lt;br /&gt;
&lt;br /&gt;
=== Scripts List ===&lt;br /&gt;
When selecting a project and opening the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab, all scripts in the project can be seen. Scripts list shows following information:&lt;br /&gt;
* &#039;&#039;&#039;Name&#039;&#039;&#039;: Name of the script.&lt;br /&gt;
* &#039;&#039;&#039;Status&#039;&#039;&#039;: Status of the script, which is one of following: &#039;&#039;Ready&#039;&#039;, &#039;&#039;Running&#039;&#039; or &#039;&#039;Stopping&#039;&#039;. For more information about script statuses, see below.&lt;br /&gt;
* &#039;&#039;&#039;Last run duration&#039;&#039;&#039;: Duration of the last ended run of the script (the last run result can be any).&lt;br /&gt;
* &#039;&#039;&#039;Last run date&#039;&#039;&#039;: Date and time when the last run ended. If you need to know the last run start time, subtract the &#039;&#039;Last run duration&#039;&#039; from this time.&lt;br /&gt;
* &#039;&#039;&#039;Last run result&#039;&#039;&#039;: Result of the last run of the script. Either of following: &#039;&#039;Completed&#039;&#039;, &#039;&#039;Failed&#039;&#039; or &#039;&#039;Aborted&#039;&#039;. For more information about last run results, see below.&lt;br /&gt;
* &#039;&#039;&#039;Id&#039;&#039;&#039;: Script id that uniquely identifies the script in the system.&lt;br /&gt;
&lt;br /&gt;
Scrips are in either of following statuses:&lt;br /&gt;
* &#039;&#039;&#039;Ready&#039;&#039;&#039;: Script is currently not running, and can be started.&lt;br /&gt;
* &#039;&#039;&#039;Running&#039;&#039;&#039;: Script is currently running, and the script can be stopped. When a script is running, another run of the same script cannot be started.&lt;br /&gt;
* &#039;&#039;&#039;Stopping&#039;&#039;&#039;: Script is currently being stopped. When a script is in this status, the script cannot be started nor stopped, so you need to wait for the script to stop. There may be a delay in stopping a script, depending on the operation currently performed by the script.&lt;br /&gt;
&lt;br /&gt;
The last script run result can be either of the following:&lt;br /&gt;
* &#039;&#039;&#039;Completed&#039;&#039;&#039;: The last run ended successfully, i.e. without any errors or exceptions. Note that despite of the technically successful run, the script might still not work as intended.&lt;br /&gt;
* &#039;&#039;&#039;Failed&#039;&#039;&#039;: The last run ended to an error or exception. To see more information about the reason of the failure, see the [[#Viewing_Script_Log|last run log]].&lt;br /&gt;
* &#039;&#039;&#039;Aborted&#039;&#039;&#039;: The last run was stopped by a user, so the script did not run till the end.&lt;br /&gt;
&lt;br /&gt;
=== Script Properties ===&lt;br /&gt;
WIP&lt;br /&gt;
&lt;br /&gt;
=== Editing Script ===&lt;br /&gt;
Open the scripts editor as follows:&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and in the right-click context menu select &#039;&#039;&#039;Edit&#039;&#039;&#039;. Alternatively, you can hover the script and click the &#039;&#039;Edit&#039;&#039; button in the end of the row.&lt;br /&gt;
&lt;br /&gt;
The script editor can show multiple scripts in the tabs, allowing to easily switch between the scrips. The editor remembers all scripts that have been opened during the session.&lt;br /&gt;
&lt;br /&gt;
In the script editor, you can:&lt;br /&gt;
* Run the script by clicking the &#039;&#039;&#039;Run&#039;&#039;&#039; button.&lt;br /&gt;
* Stop a running script by clicking the &#039;&#039;&#039;Stop&#039;&#039;&#039; button.&lt;br /&gt;
* Save a script having unsaved changes by clicking the &#039;&#039;&#039;Save&#039;&#039;&#039; button.&lt;br /&gt;
* To run a script having unsaved changes, click the &#039;&#039;&#039;Save and Run&#039;&#039;&#039; button. Note that the script needs to be saved to run it.&lt;br /&gt;
* To go back to the list of scripts, click the &#039;&#039;&#039;Go back&#039;&#039;&#039; button. If there are unsaved changes in any of the opened scripts, you need to either save or cancel the changes.&lt;br /&gt;
* To close a script, click the &#039;&#039;Close&#039;&#039; button for the tab showing the script. If there are unsaved changes, you need to either save or cancel changes.&lt;br /&gt;
&lt;br /&gt;
=== Starting Script ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and in the right-click context menu select &#039;&#039;&#039;Run&#039;&#039;&#039;. Alternatively, you can hover the script and click the &#039;&#039;Run&#039;&#039; button in the end of the row.&lt;br /&gt;
&lt;br /&gt;
Note that when running a script in the UI, the script must not contain commands where &#039;&#039;ExecuteInClientSide&#039;&#039; is enabled, because that is only supported when running scripts using [[QPR_ProcessAnalyzer_ScriptLauncher|QPR ScriptLauncher]].&lt;br /&gt;
&lt;br /&gt;
=== Stopping Script ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and from the right-click context menu select &#039;&#039;&#039;Stop&#039;&#039;&#039;. Alternatively, you can hover the script and click the &#039;&#039;Stop&#039;&#039; button in the end of the row.&lt;br /&gt;
&lt;br /&gt;
Note that it may take a while for a script to actually stop, depending on what kind of operation the script is executing when it&#039;s stopped.&lt;br /&gt;
&lt;br /&gt;
=== Viewing Script Log ===&lt;br /&gt;
It&#039;s possible to see the script log of the last run, and monitor the currently running script progress. Logs for older runs are not available in the UI, nut they are stored by the system.&lt;br /&gt;
&lt;br /&gt;
To see the logs:&lt;br /&gt;
# On the left side projects hierarchy, select the project where the script is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script and in the right-click context menu select either &#039;&#039;&#039;View last run log&#039;&#039;&#039; or &#039;&#039;&#039;View current run log&#039;&#039;&#039;. (The script needs to be running to open the current run log.)&lt;br /&gt;
# If keeping the current run log open, the latest log entries are updated automatically every two seconds.&lt;br /&gt;
&lt;br /&gt;
More information about [[QPR_ProcessAnalyzer_Logs#Script_Log|Script Log]].&lt;br /&gt;
&lt;br /&gt;
=== Creating Script ===&lt;br /&gt;
# On the left side projects hierarchy, select the project where you want to create a script.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Click the &#039;&#039;&#039;New&#039;&#039;&#039; button and click &#039;&#039;&#039;Script&#039;&#039;&#039;. Define a name for the script and the scripting &#039;&#039;&#039;Language&#039;&#039;&#039; (either &#039;&#039;&#039;Expression&#039;&#039;&#039; or &#039;&#039;&#039;SQL&#039;&#039;&#039;), and then click &#039;&#039;&#039;Create&#039;&#039;&#039;. Note that script names must be unique within a project.&lt;br /&gt;
&lt;br /&gt;
Note that the scripting language cannot be changed after the script has been created, so a new script needs to be created to change the language.&lt;br /&gt;
&lt;br /&gt;
Note that each script in the same project needs to have a unique name.&lt;br /&gt;
&lt;br /&gt;
=== Deleting Script ===&lt;br /&gt;
# Select the project where the script(s) to be deleted are located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select one or several scripts to be deleted.&lt;br /&gt;
# Click the &#039;&#039;&#039;Delete&#039;&#039;&#039; button and click &#039;&#039;&#039;Delete&#039;&#039;&#039; to the confirmation message.&lt;br /&gt;
&lt;br /&gt;
Note that if the script is being run, it cannot be deleted.&lt;br /&gt;
&lt;br /&gt;
=== Renaming Script ===&lt;br /&gt;
# Select the project where the script to be renamed is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script to be renamed.&lt;br /&gt;
# Click the &#039;&#039;&#039;Rename&#039;&#039;&#039; button.&lt;br /&gt;
# Change the script name in the opening dialog and click &#039;&#039;&#039;OK&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Moving Script ===&lt;br /&gt;
Scripts can be moved by dragging them with the left mouse button from the right side list to the target project in the left side hierarchy. Alternatively, you can first select the scripts, then from the right-click context menu select &#039;&#039;&#039;Move to&#039;&#039;&#039; and finally select the target project.&lt;br /&gt;
&lt;br /&gt;
=== Duplicating Script ===&lt;br /&gt;
# Select the project where the script to be duplicated is located.&lt;br /&gt;
# Open the &#039;&#039;&#039;Scripts&#039;&#039;&#039; tab.&lt;br /&gt;
# Select the script to be duplicated.&lt;br /&gt;
# Click the &#039;&#039;&#039;Duplicate&#039;&#039;&#039; button. A duplicate of the script is created.&lt;br /&gt;
&lt;br /&gt;
=== Viewing Script Run Results ===&lt;br /&gt;
Script runs can be [[Managing_Scripts#Running_Script|started]] and [[Managing_Scripts#Stopping_Script|stopped]] in the UI. Note that when running scripts using the UI, return values or results of the script cannot be viewed. If you want to use scripts that return data, there are following options:&lt;br /&gt;
* Script can write data to the script log&lt;br /&gt;
* Script can write data to a datatable&lt;br /&gt;
* Script can be called from a dashboard and use the dashboard to present the returned data (see more below).&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=PA_Configuration_database_table&amp;diff=28056</id>
		<title>PA Configuration database table</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=PA_Configuration_database_table&amp;diff=28056"/>
		<updated>2026-04-09T09:18:28Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63184&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer database has a configuration table &#039;&#039;&#039;PA_Configuration&#039;&#039;&#039; containing settings listed in the tables below. You need &#039;&#039;&#039;SQL Server Management Studio&#039;&#039;&#039; to edit the settings in the configuration table. QPR ProcessAnalyzer Server needs to be restarted (e.g. IIS application pool recycled) for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
For boolean values, &#039;&#039;true&#039;&#039; and &#039;&#039;1&#039;&#039; are valid values for yes, and &#039;&#039;false&#039;&#039; and &#039;&#039;0&#039;&#039; are valid for no.&lt;br /&gt;
&lt;br /&gt;
== General Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||DefaultDataSource&lt;br /&gt;
||&lt;br /&gt;
||Datasource where datatables data is stored when datatables are created by a script when the datasource is not explicitly specified in the script. Options are &#039;&#039;&#039;Snowflake&#039;&#039;&#039; and &#039;&#039;&#039;SqlServer&#039;&#039;&#039;. Value &#039;&#039;snowflake&#039;&#039; can be used when the &#039;&#039;SnowflakeConnectionString&#039;&#039; setting is defined, and value &#039;&#039;sqlserver&#039;&#039; can be used when the setting &#039;&#039;SqlServerConnectionString&#039;&#039; is configured. The setting can be changed without affecting the existing datatables, as the setting only affect new datatables. When this setting is empty, datatables are created in the metadata database.&lt;br /&gt;
|-&lt;br /&gt;
||SnowflakeConnectionString&lt;br /&gt;
||&lt;br /&gt;
||ODBC connection string for the Snowflake account. This setting is needed to make analytics calculations in the Snowflake. More information how to configure the [[Snowflake_Connection_Configuration#Set_Snowflake_ODBC_connection|Snowflake connection string]]. The Snowflake ODBC driver also needs to be installed in the machine running the QPR ProcessAnalyzer Server. When this setting has been configured, users can create Snowflake stored datatables and models using Snowflake calculation.&lt;br /&gt;
&lt;br /&gt;
When running QPR ProcessAnalyzer in the Snowpark Container Services, leave the SnowflakeConnectionString empty because then the connection string is created automatically using the method provided by the Snowpark Container Services.&lt;br /&gt;
|-&lt;br /&gt;
||SqlServerConnectionString&lt;br /&gt;
||&lt;br /&gt;
||Connection string for the SQL Server database containing the datatables data. It&#039;s recommended to use a separate database, but it&#039;s also possible to connect to the same database as the configuration data. If this setting is not configured, local datatables cannot be created (SQL Server stored). Existing datatables located in the configuration datatabase still work even if this setting has not be configured. Note that the connection uses ADO.Net (not ODBC), so the connection string is similar to the configuration database ([[Server_settings_in_appsettings.json|appsettings.json]] file).&lt;br /&gt;
|-&lt;br /&gt;
||DefaultColorPalette&lt;br /&gt;
||&lt;br /&gt;
||Charts color palette used globally in the environment. Defined as a json array of strings encoded with RGB hex (with or without alpha). Note that when a color palette in a chart has been changed, the chart starts using a chart-specific color palette, and the global color palette doesn&#039;t affect those charts. &lt;br /&gt;
&lt;br /&gt;
Example: [&amp;quot;#1F77B4&amp;quot;, &amp;quot;#FF7F0E&amp;quot;, &amp;quot;#2CA02C&amp;quot;, &amp;quot;#D62728&amp;quot;, &amp;quot;#9467BD&amp;quot;, &amp;quot;#8C564B&amp;quot;, &amp;quot;#E377C2&amp;quot;, &amp;quot;#7F7F7F&amp;quot;, &amp;quot;#BCBD22&amp;quot;, &amp;quot;#17BECF&amp;quot;]&lt;br /&gt;
|-&lt;br /&gt;
||OpenAIAPIKey&lt;br /&gt;
||&lt;br /&gt;
||API key for the OpenAI API (https://platform.openai.com/docs/api-reference). It needs to be configured to use the [[AI_Assistant_for_QPR_ProcessAnalyzer|AI Assistant]] and [[Generic_Functions_in_QPR_ProcessAnalyzer#OpenAIChatCompletion|OpenAIChatCompletion]] function.&lt;br /&gt;
|-&lt;br /&gt;
||OpenAIDefaultModelName&lt;br /&gt;
||gpt-4o&lt;br /&gt;
||OpenAI large language model (LLM) to use for the [[AI_Assistant_for_QPR_ProcessAnalyzer|AI Assistant]] and [[Generic_Functions_in_QPR_ProcessAnalyzer#OpenAIChatCompletion|OpenAIChatCompletion]] function. If not defined, &#039;&#039;&#039;gpt-4o&#039;&#039;&#039; will be used. Note that only LLM&#039;s that support the function calling feature, are suitable for the AI Assistant. More information about OpenAI models: https://platform.openai.com/docs/models.&lt;br /&gt;
|-&lt;br /&gt;
||DefaultCortexAgentsModelName&lt;br /&gt;
||llama3.1-70b&lt;br /&gt;
||Specifies the default language model when using Snowflake Cortex Agents (https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-agents-rest-api). If not defined, &#039;&#039;&#039;llama3.1-70b&#039;&#039;&#039; is used.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;QueryTimeout&amp;quot;&amp;gt;QueryTimeout&amp;lt;/span&amp;gt;&lt;br /&gt;
||300&lt;br /&gt;
||Timeout (in seconds) for requests made to /api/expression/query and /api/expression endpoints. When the timeout is exceeded, the query is stopped and a timeout error is returned. Purpose of the timeout is to protect the system against potentially too long running or even never-ending queries which might otherwise jam the system.&lt;br /&gt;
|-&lt;br /&gt;
||SessionIdleTimeout&lt;br /&gt;
||3600&lt;br /&gt;
||Idle user session expiration timeout in seconds. User session expires if the session hasn&#039;t been used after this amount of time.&lt;br /&gt;
|-&lt;br /&gt;
||SessionMaximumDuration&lt;br /&gt;
||86400&lt;br /&gt;
||Maximum duration for a user session in seconds. Even if a session is used so that the SessionIdleTimeout is not reached, the session is expired after this amount of time.&lt;br /&gt;
|-&lt;br /&gt;
|DatabaseId&lt;br /&gt;
|&lt;br /&gt;
||Unique identifier for the QPR ProcessAnalyzer environment. Any characters between a-z, A-Z, 0-9 and _ (underscore) can be used in the DatabaseId. If the DatabaseId is missing or set to null, the system will generate a new GUID during startup and use it as the DatabaseId. The DatabaseId can also be an empty string. If using several QPR ProcessAnalyzer environments, make sure each use a different DatabaseId. The DatabaseId is used as part of the table names in Snowflake and SQL Server (in the datatables database). Thus if the DatabaseId is changed, all tables in Snowflake and SQL Server named with qprpa_dt_&amp;lt;DatabaseId&amp;gt;_&amp;lt;DatatableId&amp;gt; need to be renamed.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;CacheOnlyPrimaryKeysForFilters&amp;quot;&amp;gt;CacheOnlyPrimaryKeysForFilters&amp;lt;/span&amp;gt;&lt;br /&gt;
||false&lt;br /&gt;
||Defines whether to include all columns in the Snowflake event cache filter tables (&#039;&#039;false&#039;&#039;), or only the primary key columns (&#039;&#039;true&#039;&#039;). When &#039;&#039;false&#039;&#039;, cache table creation is slower, but the analysis calculation is faster because the original event table is not used anymore. When &#039;&#039;false&#039;&#039;, also the cache tables require more storage space in Snowflake.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Localization Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||DefaultUiLanguage&lt;br /&gt;
||en_US&lt;br /&gt;
||Language code for the UI language that new user accounts get by default. Thus, a created user account has this language until the user changes her/his language. Also the login page is translated using this language when QPR ProcessAnalyzer is used for the first time in that web browser (when user has changed the language, it&#039;s remembered by the browser). This setting must be one of the supported language codes (xx_XX):&lt;br /&gt;
* English: &#039;&#039;&#039;en_US&#039;&#039;&#039;&lt;br /&gt;
* Finnish: &#039;&#039;&#039;fi_FI&#039;&#039;&#039;&lt;br /&gt;
* French: &#039;&#039;&#039;fr_FR&#039;&#039;&#039;&lt;br /&gt;
* German: &#039;&#039;&#039;de_DE&#039;&#039;&#039;&lt;br /&gt;
* Polish: &#039;&#039;&#039;pl_PL&#039;&#039;&#039;&lt;br /&gt;
* Portuguese: &#039;&#039;&#039;pt_BR&#039;&#039;&#039;&lt;br /&gt;
* Spanish: &#039;&#039;&#039;es_ES&#039;&#039;&#039;&lt;br /&gt;
* Swedish: &#039;&#039;&#039;sv_SE&#039;&#039;&#039;&lt;br /&gt;
* Ukrainian: &#039;&#039;&#039;uk_UK&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||DefaultDateFormat&lt;br /&gt;
||MM/dd/yyyy&lt;br /&gt;
||Default date format that new user accounts get by default. The date format does not contain the time part (e.g. hours, minutes and seconds). Defined using the .Net date format (https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings).&lt;br /&gt;
|-&lt;br /&gt;
||DefaultFirstDayOfWeek&lt;br /&gt;
||0&lt;br /&gt;
||Default first day of the week that new user accounts get by default. &#039;&#039;&#039;0&#039;&#039;&#039; is Sunday and &#039;&#039;&#039;1&#039;&#039;&#039; is Monday. This information is used by the UI when showing e.g. calendars.&lt;br /&gt;
|-&lt;br /&gt;
||DefaultUse12HourClock&lt;br /&gt;
||false&lt;br /&gt;
||Defines whether the 12-hour clock is used by default (instead of the 24-hour clock) for the new user accounts when showing time information in the UI. Defined as &#039;&#039;&#039;true&#039;&#039;&#039; or &#039;&#039;&#039;false&#039;&#039;&#039;. More information about the 12-hour clock: https://en.wikipedia.org/wiki/12-hour_clock.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== ETL Scripts Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||AllowExternalDatasources&lt;br /&gt;
||true&lt;br /&gt;
||Can be used to disallow all connections to external datasources in the expression language and SQL scripts to improve security. Disallowed operations include ODBC, OLE DB, SQL Server (Ado.Net), SAP, Salesforce, and call web service. Note that this setting does not prevent the Snowflake processing. Regardless of this setting, QPR ScriptLauncher can be used to extract data from source systems.&lt;br /&gt;
|-&lt;br /&gt;
||SandboxDatabaseConnectionString&lt;br /&gt;
||&lt;br /&gt;
||Connection string to scripting sandbox database (ETL). If not defined, SQL-based ETL scripts cannot be run. Connection string for the scripting sandbox database is similar to the  [[Server_settings_in_appsettings.json|QPR ProcessAnalyzer database connection string]]. More information: [[Setting up Scripting Sandbox]].&lt;br /&gt;
|-&lt;br /&gt;
||AllowNonTemporaryETLTargetTable&lt;br /&gt;
||false&lt;br /&gt;
||Defined whether ETL scripts are allowed to create global temporary database tables (tables starting with ##). More information about temporary tables: https://docs.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql?view=sql-server-ver15#temporary-tables.&lt;br /&gt;
|-&lt;br /&gt;
||DatabaseBulkCopyTimeout&lt;br /&gt;
||600&lt;br /&gt;
||Timeout used for data import operations to datatables.&lt;br /&gt;
|-&lt;br /&gt;
|SandboxDatabaseBulkCopyTimeout&lt;br /&gt;
||600&lt;br /&gt;
||Timeout used for data import operations to sandbox tables in the SQL scripts.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;DatabaseBulkCopyBatchSize&amp;lt;/span&amp;gt;&lt;br /&gt;
||5000&lt;br /&gt;
||BulkCopyBatchSize given for QPR ProcessAnalyzer database SqlBulkCopy operations.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;SandboxDatabaseBulkCopyBatchSize&amp;lt;/span&amp;gt;&lt;br /&gt;
||5000&lt;br /&gt;
||BulkCopyBatchSize given for sandbox SqlBulkCopy operations.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== In-memory Calculation Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||NumberOfParallelModelReaders&lt;br /&gt;
||4&lt;br /&gt;
||Models and datatable contents can be loaded with multiple simultaneous connections to the database to speed up the loading. This setting determines how many parallel loaders/readers at maximum (loaders are loading at the same time). For smaller models there are less parallel loaders than the defined limit: If there are less than 100000 rows in the table, there is only one loader. If there are less than 200000 rows in the table, there are only two loaders, and so on. &lt;br /&gt;
&lt;br /&gt;
The more there are parallel loaders, the more processor load and network bandwidth is consumed, and other operations in QPR ProcessAnalyzer might slow down. Note also that the performance optimum is achieved with a certain number of parallel loaders which differs between environment. Thus to achieve the best performance, data loading should be tested with different number of parallel loaders. Increasing number of parallel loaders beyond the optimum decreases the performance.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
||StartupModelLoadingMaxParallelism&lt;br /&gt;
||2&lt;br /&gt;
||Maximum number of QPR ProcessAnalyzer models that are loaded into memory simultaneously by the [[Automatic_Model_Loading_on_Server_Startup|Automatic Loading on Server Startup]]. If there are more models to be loaded on the server startup than this setting, loading for the rest of the models is started one by one when previous model loadings are completed. If this setting is not defined, &#039;&#039;&#039;2&#039;&#039;&#039; is used as a default value.&lt;br /&gt;
&lt;br /&gt;
Loading more models at the same time will speed up the whole model loading process, but on the other hand, it causes more load on the system, which affects the system responsiveness for users. Model loading consists of (1) transferring data from the datasource to QPR ProcessAnalyzer and (2) loaded data preprocessing into a model. The former uses mainly network bandwidth (if datasource is in a different server) and the latter uses mainly processor capacity in the QPR ProcessAnalyzer server. &lt;br /&gt;
&lt;br /&gt;
This setting affects only the model loading during the server startup and it doesn&#039;t restrict models loadings initiated by users.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== SAML 2.0 Federated Authentication Settings ==&lt;br /&gt;
Note that the SAMLMetadataUrl and ServiceProviderLocation are mandatory for the federated authentication to work. Having both ExternalOAuthServerConfiguration and SAML authentication configured at the same time is not supported.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||SAMLMetadataUrl&lt;br /&gt;
||&lt;br /&gt;
Metadata URL of the identity provider (IdP). Check that the metadata url can actually be opened using a web browser and is publicly available. The metadata is an XML document starting with &#039;&#039;&#039;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&#039;&#039;&#039; followed by an &#039;&#039;&#039;EntityDescriptor&#039;&#039;&#039; tag. The metadata URL might look &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;https://your.federated.identity.provider.com/saml/metadata&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;. This setting is mandatory for the SAML authentication to work.&lt;br /&gt;
|-&lt;br /&gt;
||ServiceProviderLocation&lt;br /&gt;
||&lt;br /&gt;
Specifies the QPR ProcessAnalyzer server location (the root path which contains e.g. the &#039;&#039;ui&#039;&#039; folder). It&#039;s used by the url to redirect back to QPR ProcessAnalyzer after a successful authentication from the identity provider. The setting is defined in the following form: &#039;&#039;&#039;https://&amp;lt;hostname&amp;gt;/qprpa&#039;&#039;&#039;, for example &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;https://customer.onqpr.com/qprpa&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;. Note that the actual redirect back url is &#039;&#039;&#039;https://&amp;lt;hostname&amp;gt;/qprpa/api/Saml2/Acs&#039;&#039;&#039; (/api/Saml2/Acs is automatically included to the url). This setting is mandatory for the SAML authentication to work. Note that if this reply url is configured the identity provider, it must match with the ServiceProviderLocation setting.&lt;br /&gt;
|-&lt;br /&gt;
||SAMLUserIdAttribute&lt;br /&gt;
||&lt;br /&gt;
Name of the SAML attribute in the assertion that will be used as the user&#039;s login name. If this field is not defined, the &#039;&#039;&#039;saml:Assertion&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:Subject&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:NameID&#039;&#039;&#039; attribute in the assertion is used. If this setting is given, one of the &#039;&#039;&#039;saml:Assertion&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:AttributeStatement&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:Attribute&#039;&#039;&#039; elements in the assertion is used (the &#039;&#039;&#039;Name&#039;&#039;&#039; attribute in the &#039;&#039;&#039;saml:Attribute&#039;&#039;&#039; element is used for matching). Please note that the saml:NameID element is different than the usual SAML attributes that are defined by the saml:Attribute elements. For example, if an email address is used as a user id, the value of the setting could be for example &#039;&#039;&amp;lt;nowiki&amp;gt;http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress&amp;lt;/nowiki&amp;gt;&#039;&#039;.&lt;br /&gt;
|-&lt;br /&gt;
||SAMLGroupsAttribute&lt;br /&gt;
||Attribute name in SAML assertion that is mapped to user groups in QPR ProcessAnalyzer. The user group names are case sensitive. When a user logs in, the user is added to and removed from groups based on the information in the SAML assertion. If this setting is not configured, users are not added to or removed from groups automatically. Note that the user needs to login for the groups to be synchronized. If a group doesn&#039;t exist in QPR ProcessAnalyzer, that group is skipped.&lt;br /&gt;
&lt;br /&gt;
In the SAML assertion, attributes are in the saml:Assertion &amp;gt; saml:AttributeStatement &amp;gt; saml:Attribute elements (the Name attribute in the saml:Attribute element is used for matching).&lt;br /&gt;
|-&lt;br /&gt;
||SAMLEncryptionCertificate&lt;br /&gt;
||This setting defines a PFX formatted X.509 certificate (defined in RCF 1422) used to encrypt SAML assertions. The public key of the certificate is published in the service provider metadata, where the identity provider can read it and encrypt SAML assertions. QPR ProcessAnalyzer as the service provider uses the corresponding private key of the certificate to decrypt SAML assertions. The setting needs to be a PFX formatted certificate file that is base64 encoded and it doesn&#039;t contain the BEGIN CERTIFICATE etc. header or footer lines. This setting is needed only when using the SAML assertions encryption. Even though this setting is defined, the SAML assertions are not required to be encrypted. More information how to create the certificate file (https://stackoverflow.com/questions/16480846/x-509-private-public-key) and convert it to base64 (https://stackoverflow.com/questions/46959822/base-64-encoded-form-of-the-pfx-file).&lt;br /&gt;
|-&lt;br /&gt;
||SAMLSigningCertificate&lt;br /&gt;
||This setting defines a PFX formatted X.509 certificate (defined in RCF 1422) used to sign SAML authentication requests sent from QPR ProcessAnalyzer to the identity provider. The public key of the certificate is published in the service provider metadata, where the identity provider can read it, to verify the authenticity of the SAML requests. The setting needs to be a PFX formatted certificate file that is base64 encoded and it doesn&#039;t contain the BEGIN CERTIFICATE etc. header or footer lines. If this setting is not defined, the internal hard-coded signing certificate is used. More information how to create the certificate file (https://stackoverflow.com/questions/16480846/x-509-private-public-key) and convert it to base64 (https://stackoverflow.com/questions/46959822/base-64-encoded-form-of-the-pfx-file).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OAuth 2.0 Authentication Settings ==&lt;br /&gt;
Having both ExternalOAuthServerConfiguration and SAML authentication configured at the same time is not supported.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||ExternalOAuthServerConfiguration&lt;br /&gt;
||Used to configure OAuth 2.0 compatible OAuth server settings for server that is used to authenticate the user signing in to ProcessAnalyzer. If not set, external OAuth server will not be used for authentication. If set, contains a string representation of a JSON object that supports the following properties:&lt;br /&gt;
* &#039;&#039;&#039;Authority&#039;&#039;&#039; (string): OAuth authority URL for authentication. E.g., https://accounts.google.com/&lt;br /&gt;
* &#039;&#039;&#039;Audience&#039;&#039;&#039; (string): Mandatory. OAuth audience/client ID for validating OAuth tokens.&lt;br /&gt;
* &#039;&#039;&#039;AuthorizeUrlOverride&#039;&#039;&#039; (string): Override URL for the OAuth authorization endpoint. If empty or not defined, the default URL from the authority&#039;s discovery document is used.&lt;br /&gt;
* &#039;&#039;&#039;TokenUrlOverride&#039;&#039;&#039; (string): Override URL for the OAuth token endpoint. If empty or not defined, the default URL from the authority&#039;s discovery document is used.&lt;br /&gt;
* &#039;&#039;&#039;UserInfoUrlOverride&#039;&#039;&#039; (string): Override URL to fetch user information from the OAuth provider. If empty or not defined, the default URL from the authority&#039;s discovery document is used. Should not be used if OpendID Connect is to be used as access token validation is skipped.&lt;br /&gt;
* &#039;&#039;&#039;ClientSecret&#039;&#039;&#039; (string): OAuth client secret for confidential client authentication. If configured, this value is sent as the client_secret parameter when exchanging authorization codes for tokens.&lt;br /&gt;
* &#039;&#039;&#039;Issuer&#039;&#039;&#039; (string): OAuth issuer for validating OAuth tokens. If empty, the authority URL&#039;s issuer is used.&lt;br /&gt;
* &#039;&#039;&#039;UserNameClaim&#039;&#039;&#039; (string): Name of the claim whose value is to be used as the name of the authenticated user. The default value is &amp;quot;preferred_username&amp;quot;.&lt;br /&gt;
* &#039;&#039;&#039;UserGroupsClaim&#039;&#039;&#039; (string): Name of the claim whose value is to be used as the names of the user groups the authenticated user belongs to. The default value is &amp;quot;groups&amp;quot;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== SMTP Server Settings ==&lt;br /&gt;
SMTP server settings are needed for QPR ProcessAnalyzer to send email messages. Email sending is used by the [[Email_Notifications|notifications]] and the [[Generic_Functions_in_QPR_ProcessAnalyzer#SendEmail|SendEmail]] function in the expression language.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||SmtpServer&lt;br /&gt;
||DNS name, host name or IP address of the SMTP server. Mandatory setting for the email sending to work.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpPort&lt;br /&gt;
||TCP port number of the SMTP server. If not defined, port 25 is used by default.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpAuthenticationUsername&lt;br /&gt;
||User name for authenticating to the SMTP server. If not defined, no authentication is used to connect to the SMTP server.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpFromAddress&lt;br /&gt;
||Email address where email messages sent by QPR ProcessAnalyzer appear to be coming from. This doesn&#039;t need to be a real email address, although the address used may affect email spam filters. The setting configured here is the default email address to use in following cases:&lt;br /&gt;
* &#039;&#039;From address&#039;&#039; is not set for the email notifications&lt;br /&gt;
* &#039;&#039;From&#039;&#039; parameter is not defined for the expression language &#039;&#039;SendEmail&#039;&#039; function&lt;br /&gt;
* &#039;&#039;EmailFrom&#039;&#039; parameter is not defined for the SQL Scripting SendEmail operation&lt;br /&gt;
|-&lt;br /&gt;
||SmtpAuthenticationPassword&lt;br /&gt;
||Password for authenticating to the SMTP server.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpEnableSSL&lt;br /&gt;
||Use value &#039;&#039;&#039;True&#039;&#039;&#039; or &#039;&#039;&#039;False&#039;&#039;&#039; depending whether TLS connection to the SMTP server is used or not. If not defined, &#039;&#039;False&#039;&#039; is the default value.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MCP Server Settings ==&lt;br /&gt;
MCP server settings are needed for QPR ProcessAnalyzer to act as an [[QPR_ProcessAnalyzer_as_MCP_Server|MCP server]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||McpServerConfiguration&lt;br /&gt;
||Used to configure the MCP server built-in to ProcessAnalyzer server. If not set, MCP server functionality is disabled and MCP clients can&#039;t access to this server using MCP. If set, contains a string representation of a JSON object that supports the following properties:&lt;br /&gt;
* McpApiKey: If defined and not empty, defines the API key that can be used to connect to QPR ProcessAnalyzer MCP server without any other authentication. Default value is empty.&lt;br /&gt;
|-&lt;br /&gt;
||BuiltInOAuthServerConfiguration&lt;br /&gt;
||Used to configure OAuth 2.0 compatible OAuth server settings for OAuth server built-in to ProcessAnalyzer server. If not set, built-in OAuth server functionality is disabled and clients can&#039;t connect to this server using OAuth. If set, contains a string representation of a JSON object that supports the following properties: &lt;br /&gt;
* &#039;&#039;&#039;Issuer&#039;&#039;&#039; (string): OAuth issuer, which identifies a trusted authorization server that authenticates users and issues OAuth 2.0 access tokens and JSON Web Tokens (JWTs). If not defined or empty, default value is used, which is of format: &amp;lt;QPR ProcessAnalyzer server&#039;s base URL&amp;gt;/builtin-oauth. For example: https://example.com/builtin-oauth. The default value is empty.&lt;br /&gt;
* &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; (array of strings): Array of strings that define all the accepted audiences this QPR ProcessAnalyzer server is serving. When authorizing user using OAuth, these values are matched with the audience-parameter (a.k.a. client id) of the authorization. Only requests with a value that matches a value in this array are accepted. If null, audience-parameters are not validated at all. Instead, all authorization requests will pass the audience validation check. This also enables [https://datatracker.ietf.org/doc/html/rfc7591 Dynamic Client Registration Protocol (DCR)]. The default value is an empty array.&lt;br /&gt;
* &#039;&#039;&#039;SigningKey&#039;&#039;&#039; (string): Signing key for the built-in OAuth identity provider. If empty, generates a non-deterministic key based on the physical system where QPR ProcessAnalyzer is running. NOTE: Once QPR ProcessAnalyzer server is restarted, these non-deterministic keys no longer work. If defined, string must contain the key either in PEM ([https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rsa.importfrompem?view=net-10.0 RFC 7468 PEM-encoded key]) or JSON ([https://datatracker.ietf.org/doc/html/rfc7517 RFC 7517]) format. The default value is empty.&lt;br /&gt;
* &#039;&#039;&#039;TokenLifetimeSeconds&#039;&#039;&#039; (integer): Token lifetime in seconds for the built-in OAuth identity provider. After access token created by built-in gets older than this lifetime, it becomes unusable and a new token has to be created. The default value is 3600.&lt;br /&gt;
* &#039;&#039;&#039;DisableExternalOAuthForwarding&#039;&#039;&#039; (boolean): Can be used to disable forwarding OAuth requests to any configured external OAuth authorization server or SAML identity provider. If set, a QPR ProcessAnalyzer&#039;s own login view functionality is always used when authorizing a user. The default value is false.&lt;br /&gt;
Example configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Issuer&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
  &amp;quot;AcceptedAudiences&amp;quot;: [&amp;quot;qpr-processanalyzer&amp;quot;],&lt;br /&gt;
  &amp;quot;SigningKey&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
  &amp;quot;TokenLifetime&amp;quot;: 3600&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Readonly Information ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;DatabaseVersion&amp;lt;/span&amp;gt;&lt;br /&gt;
||Database schema version. It will be updated automatically when the newer version of QPR ProcessAnalyzer Server connects to the database and performs migration for the database schema.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;InitializationScriptDatabaseVersion&amp;lt;/span&amp;gt;&lt;br /&gt;
||Database version that was when the database was initialized when the software was installed. Do not change this setting.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;MinimumDatabaseVersion&amp;lt;/span&amp;gt;&lt;br /&gt;
||Minimum allowed database version for QPR ProcessAnalyzer Server connecting to the database. This is a legacy setting and it should not be used.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
	<entry>
		<id>https://wiki.onqpr.com/pa/index.php?title=PA_Configuration_database_table&amp;diff=28055</id>
		<title>PA Configuration database table</title>
		<link rel="alternate" type="text/html" href="https://wiki.onqpr.com/pa/index.php?title=PA_Configuration_database_table&amp;diff=28055"/>
		<updated>2026-04-09T09:11:09Z</updated>

		<summary type="html">&lt;p&gt;TeeHiet: TK-63184&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;QPR ProcessAnalyzer database has a configuration table &#039;&#039;&#039;PA_Configuration&#039;&#039;&#039; containing settings listed in the tables below. You need &#039;&#039;&#039;SQL Server Management Studio&#039;&#039;&#039; to edit the settings in the configuration table. QPR ProcessAnalyzer Server needs to be restarted (e.g. IIS application pool recycled) for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
For boolean values, &#039;&#039;true&#039;&#039; and &#039;&#039;1&#039;&#039; are valid values for yes, and &#039;&#039;false&#039;&#039; and &#039;&#039;0&#039;&#039; are valid for no.&lt;br /&gt;
&lt;br /&gt;
== General Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||DefaultDataSource&lt;br /&gt;
||&lt;br /&gt;
||Datasource where datatables data is stored when datatables are created by a script when the datasource is not explicitly specified in the script. Options are &#039;&#039;&#039;Snowflake&#039;&#039;&#039; and &#039;&#039;&#039;SqlServer&#039;&#039;&#039;. Value &#039;&#039;snowflake&#039;&#039; can be used when the &#039;&#039;SnowflakeConnectionString&#039;&#039; setting is defined, and value &#039;&#039;sqlserver&#039;&#039; can be used when the setting &#039;&#039;SqlServerConnectionString&#039;&#039; is configured. The setting can be changed without affecting the existing datatables, as the setting only affect new datatables. When this setting is empty, datatables are created in the metadata database.&lt;br /&gt;
|-&lt;br /&gt;
||SnowflakeConnectionString&lt;br /&gt;
||&lt;br /&gt;
||ODBC connection string for the Snowflake account. This setting is needed to make analytics calculations in the Snowflake. More information how to configure the [[Snowflake_Connection_Configuration#Set_Snowflake_ODBC_connection|Snowflake connection string]]. The Snowflake ODBC driver also needs to be installed in the machine running the QPR ProcessAnalyzer Server. When this setting has been configured, users can create Snowflake stored datatables and models using Snowflake calculation.&lt;br /&gt;
&lt;br /&gt;
When running QPR ProcessAnalyzer in the Snowpark Container Services, leave the SnowflakeConnectionString empty because then the connection string is created automatically using the method provided by the Snowpark Container Services.&lt;br /&gt;
|-&lt;br /&gt;
||SqlServerConnectionString&lt;br /&gt;
||&lt;br /&gt;
||Connection string for the SQL Server database containing the datatables data. It&#039;s recommended to use a separate database, but it&#039;s also possible to connect to the same database as the configuration data. If this setting is not configured, local datatables cannot be created (SQL Server stored). Existing datatables located in the configuration datatabase still work even if this setting has not be configured. Note that the connection uses ADO.Net (not ODBC), so the connection string is similar to the configuration database ([[Server_settings_in_appsettings.json|appsettings.json]] file).&lt;br /&gt;
|-&lt;br /&gt;
||DefaultColorPalette&lt;br /&gt;
||&lt;br /&gt;
||Charts color palette used globally in the environment. Defined as a json array of strings encoded with RGB hex (with or without alpha). Note that when a color palette in a chart has been changed, the chart starts using a chart-specific color palette, and the global color palette doesn&#039;t affect those charts. &lt;br /&gt;
&lt;br /&gt;
Example: [&amp;quot;#1F77B4&amp;quot;, &amp;quot;#FF7F0E&amp;quot;, &amp;quot;#2CA02C&amp;quot;, &amp;quot;#D62728&amp;quot;, &amp;quot;#9467BD&amp;quot;, &amp;quot;#8C564B&amp;quot;, &amp;quot;#E377C2&amp;quot;, &amp;quot;#7F7F7F&amp;quot;, &amp;quot;#BCBD22&amp;quot;, &amp;quot;#17BECF&amp;quot;]&lt;br /&gt;
|-&lt;br /&gt;
||OpenAIAPIKey&lt;br /&gt;
||&lt;br /&gt;
||API key for the OpenAI API (https://platform.openai.com/docs/api-reference). It needs to be configured to use the [[AI_Assistant_for_QPR_ProcessAnalyzer|AI Assistant]] and [[Generic_Functions_in_QPR_ProcessAnalyzer#OpenAIChatCompletion|OpenAIChatCompletion]] function.&lt;br /&gt;
|-&lt;br /&gt;
||OpenAIDefaultModelName&lt;br /&gt;
||gpt-4o&lt;br /&gt;
||OpenAI large language model (LLM) to use for the [[AI_Assistant_for_QPR_ProcessAnalyzer|AI Assistant]] and [[Generic_Functions_in_QPR_ProcessAnalyzer#OpenAIChatCompletion|OpenAIChatCompletion]] function. If not defined, &#039;&#039;&#039;gpt-4o&#039;&#039;&#039; will be used. Note that only LLM&#039;s that support the function calling feature, are suitable for the AI Assistant. More information about OpenAI models: https://platform.openai.com/docs/models.&lt;br /&gt;
|-&lt;br /&gt;
||DefaultCortexAgentsModelName&lt;br /&gt;
||llama3.1-70b&lt;br /&gt;
||Specifies the default language model when using Snowflake Cortex Agents (https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-agents-rest-api). If not defined, &#039;&#039;&#039;llama3.1-70b&#039;&#039;&#039; is used.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;QueryTimeout&amp;quot;&amp;gt;QueryTimeout&amp;lt;/span&amp;gt;&lt;br /&gt;
||300&lt;br /&gt;
||Timeout (in seconds) for requests made to /api/expression/query and /api/expression endpoints. When the timeout is exceeded, the query is stopped and a timeout error is returned. Purpose of the timeout is to protect the system against potentially too long running or even never-ending queries which might otherwise jam the system.&lt;br /&gt;
|-&lt;br /&gt;
||SessionIdleTimeout&lt;br /&gt;
||3600&lt;br /&gt;
||Idle user session expiration timeout in seconds. User session expires if the session hasn&#039;t been used after this amount of time.&lt;br /&gt;
|-&lt;br /&gt;
||SessionMaximumDuration&lt;br /&gt;
||86400&lt;br /&gt;
||Maximum duration for a user session in seconds. Even if a session is used so that the SessionIdleTimeout is not reached, the session is expired after this amount of time.&lt;br /&gt;
|-&lt;br /&gt;
|DatabaseId&lt;br /&gt;
|&lt;br /&gt;
||Unique identifier for the QPR ProcessAnalyzer environment. Any characters between a-z, A-Z, 0-9 and _ (underscore) can be used in the DatabaseId. If the DatabaseId is missing or set to null, the system will generate a new GUID during startup and use it as the DatabaseId. The DatabaseId can also be an empty string. If using several QPR ProcessAnalyzer environments, make sure each use a different DatabaseId. The DatabaseId is used as part of the table names in Snowflake and SQL Server (in the datatables database). Thus if the DatabaseId is changed, all tables in Snowflake and SQL Server named with qprpa_dt_&amp;lt;DatabaseId&amp;gt;_&amp;lt;DatatableId&amp;gt; need to be renamed.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span id=&amp;quot;CacheOnlyPrimaryKeysForFilters&amp;quot;&amp;gt;CacheOnlyPrimaryKeysForFilters&amp;lt;/span&amp;gt;&lt;br /&gt;
||false&lt;br /&gt;
||Defines whether to include all columns in the Snowflake event cache filter tables (&#039;&#039;false&#039;&#039;), or only the primary key columns (&#039;&#039;true&#039;&#039;). When &#039;&#039;false&#039;&#039;, cache table creation is slower, but the analysis calculation is faster because the original event table is not used anymore. When &#039;&#039;false&#039;&#039;, also the cache tables require more storage space in Snowflake.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Localization Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||DefaultUiLanguage&lt;br /&gt;
||en_US&lt;br /&gt;
||Language code for the UI language that new user accounts get by default. Thus, a created user account has this language until the user changes her/his language. Also the login page is translated using this language when QPR ProcessAnalyzer is used for the first time in that web browser (when user has changed the language, it&#039;s remembered by the browser). This setting must be one of the supported language codes (xx_XX):&lt;br /&gt;
* English: &#039;&#039;&#039;en_US&#039;&#039;&#039;&lt;br /&gt;
* Finnish: &#039;&#039;&#039;fi_FI&#039;&#039;&#039;&lt;br /&gt;
* French: &#039;&#039;&#039;fr_FR&#039;&#039;&#039;&lt;br /&gt;
* German: &#039;&#039;&#039;de_DE&#039;&#039;&#039;&lt;br /&gt;
* Polish: &#039;&#039;&#039;pl_PL&#039;&#039;&#039;&lt;br /&gt;
* Portuguese: &#039;&#039;&#039;pt_BR&#039;&#039;&#039;&lt;br /&gt;
* Spanish: &#039;&#039;&#039;es_ES&#039;&#039;&#039;&lt;br /&gt;
* Swedish: &#039;&#039;&#039;sv_SE&#039;&#039;&#039;&lt;br /&gt;
* Ukrainian: &#039;&#039;&#039;uk_UK&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
||DefaultDateFormat&lt;br /&gt;
||MM/dd/yyyy&lt;br /&gt;
||Default date format that new user accounts get by default. The date format does not contain the time part (e.g. hours, minutes and seconds). Defined using the .Net date format (https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings).&lt;br /&gt;
|-&lt;br /&gt;
||DefaultFirstDayOfWeek&lt;br /&gt;
||0&lt;br /&gt;
||Default first day of the week that new user accounts get by default. &#039;&#039;&#039;0&#039;&#039;&#039; is Sunday and &#039;&#039;&#039;1&#039;&#039;&#039; is Monday. This information is used by the UI when showing e.g. calendars.&lt;br /&gt;
|-&lt;br /&gt;
||DefaultUse12HourClock&lt;br /&gt;
||false&lt;br /&gt;
||Defines whether the 12-hour clock is used by default (instead of the 24-hour clock) for the new user accounts when showing time information in the UI. Defined as &#039;&#039;&#039;true&#039;&#039;&#039; or &#039;&#039;&#039;false&#039;&#039;&#039;. More information about the 12-hour clock: https://en.wikipedia.org/wiki/12-hour_clock.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== ETL Scripts Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||AllowExternalDatasources&lt;br /&gt;
||true&lt;br /&gt;
||Can be used to disallow all connections to external datasources in the expression language and SQL scripts to improve security. Disallowed operations include ODBC, OLE DB, SQL Server (Ado.Net), SAP, Salesforce, and call web service. Note that this setting does not prevent the Snowflake processing. Regardless of this setting, QPR ScriptLauncher can be used to extract data from source systems.&lt;br /&gt;
|-&lt;br /&gt;
||SandboxDatabaseConnectionString&lt;br /&gt;
||&lt;br /&gt;
||Connection string to scripting sandbox database (ETL). If not defined, SQL-based ETL scripts cannot be run. Connection string for the scripting sandbox database is similar to the  [[Server_settings_in_appsettings.json|QPR ProcessAnalyzer database connection string]]. More information: [[Setting up Scripting Sandbox]].&lt;br /&gt;
|-&lt;br /&gt;
||AllowNonTemporaryETLTargetTable&lt;br /&gt;
||false&lt;br /&gt;
||Defined whether ETL scripts are allowed to create global temporary database tables (tables starting with ##). More information about temporary tables: https://docs.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql?view=sql-server-ver15#temporary-tables.&lt;br /&gt;
|-&lt;br /&gt;
||DatabaseBulkCopyTimeout&lt;br /&gt;
||600&lt;br /&gt;
||Timeout used for data import operations to datatables.&lt;br /&gt;
|-&lt;br /&gt;
|SandboxDatabaseBulkCopyTimeout&lt;br /&gt;
||600&lt;br /&gt;
||Timeout used for data import operations to sandbox tables in the SQL scripts.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;DatabaseBulkCopyBatchSize&amp;lt;/span&amp;gt;&lt;br /&gt;
||5000&lt;br /&gt;
||BulkCopyBatchSize given for QPR ProcessAnalyzer database SqlBulkCopy operations.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;SandboxDatabaseBulkCopyBatchSize&amp;lt;/span&amp;gt;&lt;br /&gt;
||5000&lt;br /&gt;
||BulkCopyBatchSize given for sandbox SqlBulkCopy operations.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== In-memory Calculation Settings ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Default&amp;amp;nbsp;value	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||NumberOfParallelModelReaders&lt;br /&gt;
||4&lt;br /&gt;
||Models and datatable contents can be loaded with multiple simultaneous connections to the database to speed up the loading. This setting determines how many parallel loaders/readers at maximum (loaders are loading at the same time). For smaller models there are less parallel loaders than the defined limit: If there are less than 100000 rows in the table, there is only one loader. If there are less than 200000 rows in the table, there are only two loaders, and so on. &lt;br /&gt;
&lt;br /&gt;
The more there are parallel loaders, the more processor load and network bandwidth is consumed, and other operations in QPR ProcessAnalyzer might slow down. Note also that the performance optimum is achieved with a certain number of parallel loaders which differs between environment. Thus to achieve the best performance, data loading should be tested with different number of parallel loaders. Increasing number of parallel loaders beyond the optimum decreases the performance.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
||StartupModelLoadingMaxParallelism&lt;br /&gt;
||2&lt;br /&gt;
||Maximum number of QPR ProcessAnalyzer models that are loaded into memory simultaneously by the [[Automatic_Model_Loading_on_Server_Startup|Automatic Loading on Server Startup]]. If there are more models to be loaded on the server startup than this setting, loading for the rest of the models is started one by one when previous model loadings are completed. If this setting is not defined, &#039;&#039;&#039;2&#039;&#039;&#039; is used as a default value.&lt;br /&gt;
&lt;br /&gt;
Loading more models at the same time will speed up the whole model loading process, but on the other hand, it causes more load on the system, which affects the system responsiveness for users. Model loading consists of (1) transferring data from the datasource to QPR ProcessAnalyzer and (2) loaded data preprocessing into a model. The former uses mainly network bandwidth (if datasource is in a different server) and the latter uses mainly processor capacity in the QPR ProcessAnalyzer server. &lt;br /&gt;
&lt;br /&gt;
This setting affects only the model loading during the server startup and it doesn&#039;t restrict models loadings initiated by users.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== SAML 2.0 Federated Authentication Settings ==&lt;br /&gt;
Note that the SAMLMetadataUrl and ServiceProviderLocation are mandatory for the federated authentication to work. Having both ExternalOAuthServerConfiguration and SAML authentication configured at the same time is not supported.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||SAMLMetadataUrl&lt;br /&gt;
||&lt;br /&gt;
Metadata URL of the identity provider (IdP). Check that the metadata url can actually be opened using a web browser and is publicly available. The metadata is an XML document starting with &#039;&#039;&#039;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&#039;&#039;&#039; followed by an &#039;&#039;&#039;EntityDescriptor&#039;&#039;&#039; tag. The metadata URL might look &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;https://your.federated.identity.provider.com/saml/metadata&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;. This setting is mandatory for the SAML authentication to work.&lt;br /&gt;
|-&lt;br /&gt;
||ServiceProviderLocation&lt;br /&gt;
||&lt;br /&gt;
Specifies the QPR ProcessAnalyzer server location (the root path which contains e.g. the &#039;&#039;ui&#039;&#039; folder). It&#039;s used by the url to redirect back to QPR ProcessAnalyzer after a successful authentication from the identity provider. The setting is defined in the following form: &#039;&#039;&#039;https://&amp;lt;hostname&amp;gt;/qprpa&#039;&#039;&#039;, for example &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;https://customer.onqpr.com/qprpa&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;. Note that the actual redirect back url is &#039;&#039;&#039;https://&amp;lt;hostname&amp;gt;/qprpa/api/Saml2/Acs&#039;&#039;&#039; (/api/Saml2/Acs is automatically included to the url). This setting is mandatory for the SAML authentication to work. Note that if this reply url is configured the identity provider, it must match with the ServiceProviderLocation setting.&lt;br /&gt;
|-&lt;br /&gt;
||SAMLUserIdAttribute&lt;br /&gt;
||&lt;br /&gt;
Name of the SAML attribute in the assertion that will be used as the user&#039;s login name. If this field is not defined, the &#039;&#039;&#039;saml:Assertion&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:Subject&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:NameID&#039;&#039;&#039; attribute in the assertion is used. If this setting is given, one of the &#039;&#039;&#039;saml:Assertion&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:AttributeStatement&#039;&#039;&#039; &amp;gt; &#039;&#039;&#039;saml:Attribute&#039;&#039;&#039; elements in the assertion is used (the &#039;&#039;&#039;Name&#039;&#039;&#039; attribute in the &#039;&#039;&#039;saml:Attribute&#039;&#039;&#039; element is used for matching). Please note that the saml:NameID element is different than the usual SAML attributes that are defined by the saml:Attribute elements. For example, if an email address is used as a user id, the value of the setting could be for example &#039;&#039;&amp;lt;nowiki&amp;gt;http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress&amp;lt;/nowiki&amp;gt;&#039;&#039;.&lt;br /&gt;
|-&lt;br /&gt;
||SAMLGroupsAttribute&lt;br /&gt;
||Attribute name in SAML assertion that is mapped to user groups in QPR ProcessAnalyzer. The user group names are case sensitive. When a user logs in, the user is added to and removed from groups based on the information in the SAML assertion. If this setting is not configured, users are not added to or removed from groups automatically. Note that the user needs to login for the groups to be synchronized. If a group doesn&#039;t exist in QPR ProcessAnalyzer, that group is skipped.&lt;br /&gt;
&lt;br /&gt;
In the SAML assertion, attributes are in the saml:Assertion &amp;gt; saml:AttributeStatement &amp;gt; saml:Attribute elements (the Name attribute in the saml:Attribute element is used for matching).&lt;br /&gt;
|-&lt;br /&gt;
||SAMLEncryptionCertificate&lt;br /&gt;
||This setting defines a PFX formatted X.509 certificate (defined in RCF 1422) used to encrypt SAML assertions. The public key of the certificate is published in the service provider metadata, where the identity provider can read it and encrypt SAML assertions. QPR ProcessAnalyzer as the service provider uses the corresponding private key of the certificate to decrypt SAML assertions. The setting needs to be a PFX formatted certificate file that is base64 encoded and it doesn&#039;t contain the BEGIN CERTIFICATE etc. header or footer lines. This setting is needed only when using the SAML assertions encryption. Even though this setting is defined, the SAML assertions are not required to be encrypted. More information how to create the certificate file (https://stackoverflow.com/questions/16480846/x-509-private-public-key) and convert it to base64 (https://stackoverflow.com/questions/46959822/base-64-encoded-form-of-the-pfx-file).&lt;br /&gt;
|-&lt;br /&gt;
||SAMLSigningCertificate&lt;br /&gt;
||This setting defines a PFX formatted X.509 certificate (defined in RCF 1422) used to sign SAML authentication requests sent from QPR ProcessAnalyzer to the identity provider. The public key of the certificate is published in the service provider metadata, where the identity provider can read it, to verify the authenticity of the SAML requests. The setting needs to be a PFX formatted certificate file that is base64 encoded and it doesn&#039;t contain the BEGIN CERTIFICATE etc. header or footer lines. If this setting is not defined, the internal hard-coded signing certificate is used. More information how to create the certificate file (https://stackoverflow.com/questions/16480846/x-509-private-public-key) and convert it to base64 (https://stackoverflow.com/questions/46959822/base-64-encoded-form-of-the-pfx-file).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OAuth 2.0 Authentication Settings ==&lt;br /&gt;
Having both ExternalOAuthServerConfiguration and SAML authentication configured at the same time is not supported.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||ExternalOAuthServerConfiguration&lt;br /&gt;
||Used to configure OAuth 2.0 compatible OAuth server settings for server that is used to authenticate the user signing in to ProcessAnalyzer. If not set, external OAuth server will not be used for authentication. If set, contains a string representation of a JSON object that supports the following properties:&lt;br /&gt;
* &#039;&#039;&#039;Authority&#039;&#039;&#039; (string): OAuth authority URL for authentication. E.g., https://accounts.google.com/&lt;br /&gt;
* &#039;&#039;&#039;Audience&#039;&#039;&#039; (string): Mandatory. OAuth audience/client ID for validating OAuth tokens.&lt;br /&gt;
* &#039;&#039;&#039;AuthorizeUrlOverride&#039;&#039;&#039; (string): Override URL for the OAuth authorization endpoint. If empty or not defined, the default URL from the authority&#039;s discovery document is used.&lt;br /&gt;
* &#039;&#039;&#039;TokenUrlOverride&#039;&#039;&#039; (string): Override URL for the OAuth token endpoint. If empty or not defined, the default URL from the authority&#039;s discovery document is used.&lt;br /&gt;
* &#039;&#039;&#039;UserInfoUrlOverride&#039;&#039;&#039; (string): Override URL to fetch user information from the OAuth provider. If empty or not defined, the default URL from the authority&#039;s discovery document is used. Should not be used if OpendID Connect is to be used as access token validation is skipped.&lt;br /&gt;
* &#039;&#039;&#039;ClientSecret&#039;&#039;&#039; (string): OAuth client secret for confidential client authentication. If configured, this value is sent as the client_secret parameter when exchanging authorization codes for tokens.&lt;br /&gt;
* &#039;&#039;&#039;Issuer&#039;&#039;&#039; (string): OAuth issuer for validating OAuth tokens. If empty, the authority URL&#039;s issuer is used.&lt;br /&gt;
* &#039;&#039;&#039;UserNameClaim&#039;&#039;&#039; (string): Name of the claim whose value is to be used as the name of the authenticated user. The default value is &amp;quot;preferred_username&amp;quot;.&lt;br /&gt;
* &#039;&#039;&#039;UserGroupsClaim&#039;&#039;&#039; (string): Name of the claim whose value is to be used as the names of the user groups the authenticated user belongs to. The default value is &amp;quot;groups&amp;quot;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== SMTP Server Settings ==&lt;br /&gt;
SMTP server settings are needed for QPR ProcessAnalyzer to send email messages. Email sending is used by the [[Email_Notifications|notifications]] and the [[Generic_Functions_in_QPR_ProcessAnalyzer#SendEmail|SendEmail]] function in the expression language.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||SmtpServer&lt;br /&gt;
||DNS name, host name or IP address of the SMTP server. Mandatory setting for the email sending to work.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpPort&lt;br /&gt;
||TCP port number of the SMTP server. If not defined, port 25 is used by default.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpAuthenticationUsername&lt;br /&gt;
||User name for authenticating to the SMTP server. If not defined, no authentication is used to connect to the SMTP server.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpFromAddress&lt;br /&gt;
||Email address where email messages sent by QPR ProcessAnalyzer appear to be coming from. This doesn&#039;t need to be a real email address, although the address used may affect email spam filters. The setting configured here is the default email address to use in following cases:&lt;br /&gt;
* &#039;&#039;From address&#039;&#039; is not set for the email notifications&lt;br /&gt;
* &#039;&#039;From&#039;&#039; parameter is not defined for the expression language &#039;&#039;SendEmail&#039;&#039; function&lt;br /&gt;
* &#039;&#039;EmailFrom&#039;&#039; parameter is not defined for the SQL Scripting SendEmail operation&lt;br /&gt;
|-&lt;br /&gt;
||SmtpAuthenticationPassword&lt;br /&gt;
||Password for authenticating to the SMTP server.&lt;br /&gt;
|-&lt;br /&gt;
||SmtpEnableSSL&lt;br /&gt;
||Use value &#039;&#039;&#039;True&#039;&#039;&#039; or &#039;&#039;&#039;False&#039;&#039;&#039; depending whether TLS connection to the SMTP server is used or not. If not defined, &#039;&#039;False&#039;&#039; is the default value.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MCP Server Settings ==&lt;br /&gt;
MCP server settings are needed for QPR ProcessAnalyzer to act as an [[QPR_ProcessAnalyzer_as_MCP_Server|MCP server]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
||McpServerConfiguration&lt;br /&gt;
||Used to configure the MCP server built-in to ProcessAnalyzer server. If not set, MCP server functionality is disabled and MCP clients can&#039;t access to this server using MCP. If set, contains a string representation of a JSON object that supports the following properties:&lt;br /&gt;
* McpApiKey: If defined and not empty, defines the API key that can be used to connect to QPR ProcessAnalyzer MCP server without any other authentication. Default value is empty.&lt;br /&gt;
|-&lt;br /&gt;
||BuiltInOAuthServerConfiguration&lt;br /&gt;
||Used to configure OAuth 2.0 compatible OAuth server settings for OAuth server built-in to ProcessAnalyzer server. If not set, built-in OAuth server functionality is disabled and clients can&#039;t connect to this server using OAuth. If set, contains a string representation of a JSON object that supports the following properties: &lt;br /&gt;
* &#039;&#039;&#039;Issuer&#039;&#039;&#039; (string): OAuth issuer, which identifies a trusted authorization server that authenticates users and issues OAuth 2.0 access tokens and JSON Web Tokens (JWTs). If not defined or empty, default value is used, which is of format: &amp;lt;QPR ProcessAnalyzer server&#039;s base URL&amp;gt;/builtin-oauth. For example: https://example.com/builtin-oauth. The default value is empty.&lt;br /&gt;
* &#039;&#039;&#039;AcceptedAudiences&#039;&#039;&#039; (array of strings): Array of strings that define all the accepted audiences this QPR ProcessAnalyzer server is serving. When authorizing user using OAuth, these values are matched with the audience-parameter (a.k.a. client id) of the authorization. Only requests with a value that matches a value in this array are accepted. If null, audience-parameters are not validated at all. Instead, all authorization requests will pass the audience validation check. This also enables [Dynamic Client Registration Protocol (DCR)](https://datatracker.ietf.org/doc/html/rfc7591). The default value is an empty array.&lt;br /&gt;
* &#039;&#039;&#039;SigningKey&#039;&#039;&#039; (string): Signing key for the built-in OAuth identity provider. If empty, generates a non-deterministic key based on the physical system where QPR ProcessAnalyzer is running. NOTE: Once QPR ProcessAnalyzer server is restarted, these non-deterministic keys no longer work. If defined, string must contain the key either in PEM ([RFC 7468 PEM-encoded key](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rsa.importfrompem?view=net-10.0)) or JSON ([RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517)) format. The default value is empty.&lt;br /&gt;
* &#039;&#039;&#039;TokenLifetimeSeconds&#039;&#039;&#039; (integer): Token lifetime in seconds for the built-in OAuth identity provider. After access token created by built-in gets older than this lifetime, it becomes unusable and a new token has to be created. The default value is 3600.&lt;br /&gt;
* &#039;&#039;&#039;DisableExternalOAuthForwarding&#039;&#039;&#039; (boolean): Can be used to disable forwarding OAuth requests to any configured external OAuth authorization server or SAML identity provider. If set, a QPR ProcessAnalyzer&#039;s own login view functionality is always used when authorizing a user. The default value is false.&lt;br /&gt;
Example configuration:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Issuer&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
  &amp;quot;AcceptedAudiences&amp;quot;: [&amp;quot;qpr-processanalyzer&amp;quot;],&lt;br /&gt;
  &amp;quot;SigningKey&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
  &amp;quot;TokenLifetime&amp;quot;: 3600&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Readonly Information ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: left&amp;quot;&lt;br /&gt;
!Name	!!Description&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;DatabaseVersion&amp;lt;/span&amp;gt;&lt;br /&gt;
||Database schema version. It will be updated automatically when the newer version of QPR ProcessAnalyzer Server connects to the database and performs migration for the database schema.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;InitializationScriptDatabaseVersion&amp;lt;/span&amp;gt;&lt;br /&gt;
||Database version that was when the database was initialized when the software was installed. Do not change this setting.&lt;br /&gt;
|-&lt;br /&gt;
||&amp;lt;span style=&amp;quot;color:lightgrey;&amp;quot;&amp;gt;MinimumDatabaseVersion&amp;lt;/span&amp;gt;&lt;br /&gt;
||Minimum allowed database version for QPR ProcessAnalyzer Server connecting to the database. This is a legacy setting and it should not be used.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>TeeHiet</name></author>
	</entry>
</feed>